기본적으로 서버사이드 렌더링은 서버에서 화면을 그려서, 클라이언트에서 html
을 내려주면 그것을 그리기만 하면된다.
요즘 클라이언트에서 지향해야할 것은 자바스크립트 번들 사이즈를 줄이기 위해, 하이브리드 서버사이드렌더링을 이용하려고한다.
res.send를 통해 generatehtml
함수로 문자열 html을 내려주면 클라이언트에서는 html문서 자체를 그려주면된다.
서버에서 응답올때까지 기다리는 시간 112.47ms
서버에서 응답올때까지 기다리는 시간 10.27s
<aside> 💡 서버에서의 data fetching이 느리면 첫 화면을 그려주는데 오래 걸리게 된다.
</aside>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Todo List</title>
</head>
<body>
<div id="app">
${Button({ id: 'add', text: '아이템 추가' })}
${Button({ id: 'delete', text: '아이템 삭제' })}
${TodoList(model.todoItems)}
</div>
<script>
document.querySelector('#add').onclick = () => {
fetch('/api/todo-items', {
method: 'post',
body: JSON.stringify({ content: '추가된 아이템' }),
headers: {
'Content-Type': 'application/json',
}
}).then(() => location.reload())
}
document.querySelector('#delete').onclick = () => {
fetch('/api/todo-items/0', { method: 'delete' }).then(() => location.reload())
}
</script>
</body>
</html>
script
태그에 자스 코드를 넣는 방식 말고, 파일로 연결하는 방식으로 바꿔본다.
해당 스크립트 파일을 main.js
라는 파일로 따로 추출한다.
// ./src/main.js
/** */
function main() {
document.querySelector('#add').onclick = () => {
fetch('/api/todo-items', {
method: 'post',
body: JSON.stringify({ content: '추가된 아이템' }),
headers: {
'Content-Type': 'application/json',
},
}).then(() => location.reload());
};
document.querySelector('#delete').onclick = () => {
fetch('/api/todo-items/0', { method: 'delete' }).then(() =>
location.reload()
);
};
}
main();
기존 html 문자열에, 해당 js 파일을 가져오는 코드를 추가한다.
export const generateHTML = async (model) => {
const data = await fetchData();
return `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Todo List</title>
</head>
<body>
<div id="app">
${TodoList(model.todoItems)}
${Button({ id: 'add', text: '아이템 추가' })}
${Button({ id: 'delete', text: '아이템 삭제' })}
${PostList(data)}
</div>
<script src="./src/main.js" type="module"></script>
</body>
</html>
`;
};
아래의 코드는 클라이언트에서 해당 js
파일에 접근 할 수 있게 만들어준다. (해당 코드를 적어주지 않으면, 404에러가 뜬다.)
app.use('/src', express.static('./src'));
해당 main.js에 접근할 수 있게 되었다.
<aside>
💡 main.js
는 우리의 첫 자바스크립트 정적 파일이다!!!! 🥰
</aside>
html
파일만을 내려주고, 브라우저가 해당 html을 파싱하면서 script
태그를 만나면 연결되있는 main.js
라는 자바스크립트 파일을 서버에서 다운 받고 실행을 하게 된다.<aside> 💡 만약 개발자 도구의 disabled javascript를 키게 되면, 해당 자바스크립트 파일을 실행 시킬수 없게 된다. 다운도 안받아 온다.
</aside>
서버에서 html을 렌더링해서, 클라이언트가 요청시 내려주면, html에 script 태그가 포함이되어있고, script태그에 연결되있는 자바스크립트 파일을 다시 서버에 요청해, 다운받는다.
브라우저는 해당 자바스크립트 파일을 모두다 다운받고, 실행을 하는데 여기서, 서버에서 그려준 html과 똑같이 자바스크립트를 이용하여, 다시한번 렌더링을 한다. 추가로 이벤트핸들러 같은 것이 부착된다.
이것을 하기 위해 서버에서는 자신이 가진 정적파일에 브라우저가 접근할 수 있도록 만들어준다.
app.use('/src', express.static('./src'));
쨌든 이미 그려진 html을 다시한번 js를 이용해 그려주는 과정을 hydration이라고 한다.