[Next.js] 우리의 사이트에 날개를 달아보자 (2)

예흠·2021년 3월 7일
0

Next

목록 보기
2/3

지난번에 이어서 서버사이드 렌더링을 알아보도록 하자! - 2편

3. 서버 데이터를 클라이언트로 전달하기

서버에서 렌더링할 때 사용한 데이터를 클라이언트도 알아야 일관성 있게 화면을 갱신할 수 있다.
지금까지는 page 속성값의 초깃값을 home이라고 가정하고 코드를 작성했다. 따라서 http://localhost:3000/about으로 접속해도 Home 컴포넌트가 렌더링됐다.

이제부터는 url에 따라 /home에 접속하면 home을 초깃값으로 사용하고, /about으로 접속하면 about을 초깃값으로 사용하도록 구현해 보자.

- HTML에 서버 데이터 넣기

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);
});
    1. 문자열로 된 주솟값을 구조체로 변환하기 위해 url 모듈을 사용한다. parsedUrl 변수는 url의 경로와 쿼리 파라미터 등의 정보를 담고 있다.
    1. pathname 앞쪽의 슬래시를 제거해서 page 변수를 만든다.
    1. url로부터 계산된 페이지 정보를 App 컴포넌트의 속성값으로 사용한다.
    1. 클라이언트에게 전달할 초기 데이터다.
    1. __DATA_FROM_SERVER__문자열을 초기 데이터로 대체한다.

- 클라이언트에서 데이터 사용하기

index.js 파일을 수정해 보자.

const initialData = window.__INITIAL_DATA__;

//...
ReactDom.hydrate(<App page={initialData} />, document.getElementById('root'));
  • 서버로부터 전달된 초기 데이터를 가져온다.
  • 전달받은 page 데이터를 속성값으로 입력한다.

코드를 빌드해서 다시 실행해 보면 http://localhost:3000/about으로 접속하면 About 컴포넌트가 렌더리오디는 것을 확인할 수 있다.

리덕슬르 사용하는 프로젝트에서는 리덕스의 상탯값을 window.__INITIAL_DATA__로 전달해서 사용할 수 있다.

4. 스타일 적용하기

리액트에서 스타일을 적용하는 방식은 다양하다. 전통적인 방식으로 CSS 파일을 별도로 작성 후 HTML 파일에 연결하면 서버사이드 렌더링 시 특별히 고민할 것은 없다. 그렇지만 css-module이나 css-in-js 방식으로 작성한다면 서버사이드 렌더링 시 추가 작업을 해야 한다. ( 초기세팅에 꼭 필요하다! )
둘 다 자바스크리보드가 실행되면서 스타일 코드가 돔에 삽입되는 방식이기 때문이다. 서버에는 돔이 없으므로 별도의 작업을 하지 않으면 서버사이드 렌더링 시 스타일 정보가 HTML에 포함되지 않는다.

styled-components로 스타일 적용해 보기

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);
});
    1. 스타일을 추출하는 데 사용될 객체를 생성한다.
    1. collectStyles 메서드에 리액트 요소를 입력하면 스타일 정보를 수집하기 위한 코드가 리액트 요소에 삽입된다. 실제 스타일 정보는 renderToString 함수의 호출이 끝나야 수집할 있다.
    1. getStyleTags 메서드를 호출하면 스타일 정보가 추출된다.
    1. 추출된 스타일 코드를 HTML에 삽입한다.

빌드하고 실행해보면

이렇게 서버에서 생성된 데이터와 getStyleTags 메서드가 반환한 스타일 코드를 확인할 수 있다.

스타일 정보가 HTML에 포함되어 전달되므로 사용자는 자바스크립트가 실행되지 않더라도 빠르게 스타일이 적용된 화면을 볼 수 있다.

다음 게시물 부터는 서버사이드 고급편과 이미지 모듈 적용을 하기 전에
넥스트 초급 편부터 진행 해볼 예정이다.

profile
노래하는 개발자입니다.

0개의 댓글