지난번에 이어서 서버사이드 렌더링을 알아보도록 하자! - 2편
서버에서 렌더링할 때 사용한 데이터를 클라이언트도 알아야 일관성 있게 화면을 갱신할 수 있다.
지금까지는 page 속성값의 초깃값을 home이라고 가정하고 코드를 작성했다. 따라서 http://localhost:3000/about으로 접속해도 Home 컴포넌트가 렌더링됐다.
이제부터는 url에 따라 /home에 접속하면 home을 초깃값으로 사용하고, /about으로 접속하면 about을 초깃값으로 사용하도록 구현해 보자.
template/index.html 파일을 다음과 같이 수정한다.
<head>
...
<title>test-ssr</title>
<script type="text/javascript">
window.__INITIAL_DATA__ = __DATA_FROM_SERVER__;
</script>
</head>
__DATA_FROM_SERVER__
부분에 필요한 데이터를 채워서 전달한다. 클라이언트는 window.__INITIAL_DATA__
를 통해서 서버의 데이터를 받을 수 있다.웹 서버 코드에서는 서버의 데이터를 HTML에 삽입해야 한다. server.js 파일을 다음과 같이 수정하자.
//...
import * as url from 'url';
//...
app.get('*', (req, res) => {
const parsedUrl = url.parse(req.url, true); // 1
const page = parsedUrl.pathname ? parsedUrl.pathname.substr(1) : 'home'; // 2
const renderString = renderToString(<App page={page} />); //3
const initialData = { page }; //4
const result = html
.replace('<div id="root"></div>', `<div id="root">${renderrtring}</div>`)
.replace(`__DATA_FROM_SERVER__`, JSON.stringify(initialData)); //5
res.send(result);
});
__DATA_FROM_SERVER__
문자열을 초기 데이터로 대체한다.index.js 파일을 수정해 보자.
const initialData = window.__INITIAL_DATA__;
//...
ReactDom.hydrate(<App page={initialData} />, document.getElementById('root'));
코드를 빌드해서 다시 실행해 보면 http://localhost:3000/about으로 접속하면 About 컴포넌트가 렌더리오디는 것을 확인할 수 있다.
리덕슬르 사용하는 프로젝트에서는 리덕스의 상탯값을 window.__INITIAL_DATA__
로 전달해서 사용할 수 있다.
리액트에서 스타일을 적용하는 방식은 다양하다. 전통적인 방식으로 CSS 파일을 별도로 작성 후 HTML 파일에 연결하면 서버사이드 렌더링 시 특별히 고민할 것은 없다. 그렇지만 css-module이나 css-in-js 방식으로 작성한다면 서버사이드 렌더링 시 추가 작업을 해야 한다. ( 초기세팅에 꼭 필요하다! )
둘 다 자바스크리보드가 실행되면서 스타일 코드가 돔에 삽입되는 방식이기 때문이다. 서버에는 돔이 없으므로 별도의 작업을 하지 않으면 서버사이드 렌더링 시 스타일 정보가 HTML에 포함되지 않는다.
npm install styled-components
그리고 App.js에 다음과 같이 코드를 추가한다.
import styled from 'styled-components'
const STDContainer = styled.div`
background-color: #aaaaaa;
border: 1px solid blue;
`;
export default function App({page}){
//...
return (
<STDContainer>
//...
</STDContainer>
);
}
기존의 div 요소를 제거하고 STDContainer 컴포넌트로 대체한다.
=> STD는 스타일드 컴포넌트와 일반 컴포넌트를 나누기 위해 붙였다.
이 상태로 빌드 후 실행해보면 브라우저에서 스타일이 잘 적용된 것을 볼 수 있다.
하지만 아직 개선할 점이 남아 있다. 서버로부터 전달된 HTML을 살펴보면 스타일 코드가 없다. 그래서 스타일이 적용되지 않은 화면이 잠시 보이고, 클라이언트에서 자바스크립트가 실행된 후에야 스타일이 적용된다.
=> 이를 개선하지 않으면 초기 화면은 깜빡이고, 검색 엔진에는 스타일이 적용되지 않은 화면이 전달된다.( 화면 다 깨짐... )
게다가 사용자의 브라우저가 자바스크립트 실행을 허용하지 않으면 스타일이 적용되지 않은 화면만 보인다.
이를 개선하기 위해서는 서버사이드 렌더링 시 스타일을 적용해야 한다.
HTML에 스타일 코드를 넣기 위해 templatee/index.html 파일을 다음과 같이 수정하자.
<!DOCTYPE html>
<html>
<head>
//...
__STYLE_FROM_SERVER__
</head>
//...
저기에 서버사이드 렌더링 시 추출된 스타일 코드를 넣을 예정이다.
server.js 파일을 다음과 같이 수정하자.
import { ServerStyleSheet } from 'styled-components'
//...
app.get('*', (req, res) => {
const parsedUrl = url.parse(req.url, true);
const page = parsedUrl.pathname ? parsedUrl.pathname.substr(1) : 'home';
const sheet = new ServerStyleSheet(); // 1
const renderString = renderToString(sheet.collectStyles(<App page={page} />)); // 2
const styles = sheet.getStyleTags(); // 3
const initialData = { page };
const result = html
.replace('<div id="root"></div>', `<div id="root">${renderString}</div>`)
.replace(`__DATA_FROM_SERVER__`, JSON.stringify(initialData))
.replace('__STYLE_FROM_SERVER__', styles); //4
res.send(result);
});
빌드하고 실행해보면
이렇게 서버에서 생성된 데이터와 getStyleTags 메서드가 반환한 스타일 코드를 확인할 수 있다.
스타일 정보가 HTML에 포함되어 전달되므로 사용자는 자바스크립트가 실행되지 않더라도 빠르게 스타일이 적용된 화면을 볼 수 있다.
다음 게시물 부터는 서버사이드 고급편과 이미지 모듈 적용을 하기 전에
넥스트 초급 편부터 진행 해볼 예정이다.