styled-components는 JS 코드를 통해 컴포넌트에 스타일을 적용하며, 이 스타일은 브라우저에서 페이지가 로드된 후 실행되는 CSR 방식으로 작동한다.
즉, 사용자가 페이지를 방문했을 때 브라우저에서 스타일이 생성되고 적용된다.
styled-components로 구현하였을 때, 스타일이 적용되지 않은 상태로 화면이 먼저 표기되고, 이후에 스타일이 적용되는 깜빡임 현상이 나타날 수 있다.
SSR 방식으로 설정하면 서버에서 렌더링 된 HTML 문서에 미리 스타일이 적용되어 전달되기 때문에 이 현상을 최소화할 수 있고, 초기 페이지 로드 속도를 개선 시킬 수 있으며 SEO 최적화에도 도움이 된다.
_documents.js
는 Next.js에서 서버 측 렌더링을 담당하는 파일 중 하나이며, HTML, HEAD, BODY 등의 기본 레이아웃을 설정해 준다.
styled-components에서 제공하는 ServerStyleSheet API
를 사용하여 서버에서 스타일 코드를 수집하여 SSR에 필요한 스타일 태그를 생성해 준다. 그리고 스타일 태그를 HTML 문서의 <head>
에 삽입하여 최초 페이지 로드 시 스타일이 적용된 상태로 보여준다.
// pages/_document.js
import { Html, Head, Main, NextScript } from 'next/document'
export default function Document() {
return (
<Html lang="en">
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
// pages/_document.js
import Document from "next/document";
import { ServerStyleSheet } from "styled-components";
export default class MyDocument extends Document {
static async getInitialProps(ctx) {
/* ServerStyleSheet를 사용하여 React 앱 전체의 스타일 수집
-> 서버 렌더링 시에도 모든 스타일이 포함됨 */
const sheet = new ServerStyleSheet();
const originalRenderPage = ctx.renderPage;
try {
/* getInitialProps 메서드에서 enhanceApp를 이용하여
ServerStyleSheet를 적용하고 스타일을 수집 */
ctx.renderPage = () =>
originalRenderPage({
enhanceApp: (App) => (props) =>
sheet.collectStyles(<App {...props} />),
});
/* getStyleElement()로 수집한 스타일이
initialProps.styles와 함께 반환 */
const initialProps = await Document.getInitialProps(ctx);
return {
...initialProps,
styles: (
<>
{initialProps.styles}
{sheet.getStyleElement()}
</>
),
};
} finally {
sheet.seal();
}
}
}
html, body 태그를 설정하고 싶으면 render(){}
에 작성하여 추가하면 된다.
import Document, { Html, Head, Main, NextScript } from "next/document";
...(생략)
render() {
return (
<Html lang="ko">
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
);
}