ssr 삽질기 - styled-component가 잘 렌더링되지 않아요!

dante Yoon·2020년 5월 17일
3

영차영차 삽질기

목록 보기
1/2
현재 진행중인 개인 프로젝트에서 처음으로 Next.js를 사용하지 않고 SSR과 코드스플리팅을 적용해보고 있습니다. 프레임워크를 사용하지 않으니 개발환경 구축에 여러모로 애를 먹었지만 리엑트 공식 문서와 stackoverflow, 페이스북 React Korea 커뮤니티등 여러 웹페이지를 왔다갔다하며 많은 사람들과 커뮤니케이션을 할 수 있었는데요,
오늘은 SSR과 코드스플리팅을 구축하며 서버에서 렌더링되는 html 파일에 스타일링이 제대로 입혀지지 않는 것을 어떻게 해결했는지에 대해 나누고자 합니다.

👉 무슨 문제가 있었나요?

webpack-dev-middleware와 webpack-hot-middleware 을 이용해서 express 서버 코드인 server.tsx에서 앱 구동시 초기 화면을 불러올때

찰나의 시간동안 스타일이 전혀 입혀지지 않은 plain text들이 화면에 표시되는 것이 문제였습니다.

SSR과 코드스프리팅의 특성상 첫 화면을 렌더링하고 동적임포트 한 chunk된 javascript들이 hydrate 되는데요, hydrate 되기 이전에 첫 렌더링 될때도 스타일이 입혀지는 것이 제가 기대했던 결과물이었습니다.

만약 위와 같이 굴러가지 않는다면 User Experience에 정말 안 좋은 영향을 미치게 될 것입니다.

👉 무슨 시도를 했었나요?

1.babel-plugin-styled-components 추가 및 옵션 설정,
2.babel.config.js 및 webpack.config 관련 파일 수정
3. styled-component 문서 리서치

개발환경 구축 시 webpack 설정에 시행착오가 많았어서 이번 문제 역시 webpack 관련 설정을 잘못해서 일어났겠거니 했는데요, 문제는 서버쪽 코드에 있었습니다.

👉 어떻게 해결을 했나요?

styled-component 모듈에서 제공하는 ServerStyleSheet 클래스가 있습니다.
해당 클래스의 getStyleTags 함수를 이용해 서버쪽에서 보내는 jsx의 style을 추출하여
index.html에 집어넣어줘야 합니다.

코드로 보여드리는게 더 명확할 것 같은데요,

import { ServerStyleSheet } from 'styled-components';
import { ChunkExtractor } from '@loadable/server';


...
const webExtractor = new ChunkExtractor('./loadable-stats.json');

const jsx = webExtractor.collectChunks(
  <StaticRouter location={req.url} context={context}>
    <App/>
  </StaticRouter>
);
const html = renderToString(sheet.collectStyles(jsx));
const helmet = Helmet.renderStatic();
const styles = sheet.getStyleTags(); 

res.send(
	`
		<!DOCTYPE html>
		<head>
			...
			${webExtractor.getStyleTags() + styles} 
			...	
		</head>
		<body>
			<div id="root">${html}</div>
		</body> 
   		... 
	`
)
profile
성장을 향한 작은 몸부림의 흔적들

0개의 댓글