[Next.js] styled-components를 Client side 렌더링 이전에 적용시키기 (덜그덕 방지, Typescript)
styled-components를 이용하여 스타일링하고 Next.js 앱을 켜면 처음에 CSS가 완전히 로딩되지 않은 듯한 모습이 보이게 되는데, 흉한 맨얼굴이 그대로 드러나니 사용자 경험이 꽤 나쁘다. 이것은 스타일이 Client side에서 적용되고 있기 때문이다. 이를 해결하기 위해서는 커스텀 Document를 만들고, ServerStyleSheet를 이용해서 <App/> 컴포넌트의 모든 스타일을 서버 사이드에서 적용될 수 있도록 바꾸어야한다.
babel-plugin-styled-components 설치
먼저 babel-plugin-styled-components를 설치한다.
yarn add babel-plugin-styled-components
.babelrc에서 SSR를 사용하도록 설정
.babelrc에는 다음과 같이 설정한다.
{
"presets": ["next/babel"],
"plugins": [["styled-components", { "ssr": true }]]
}
Custom document 작성
pages/_document.tsx를 작성한다.
import React, { ReactElement } from "react";
import Document, {
DocumentInitialProps,
DocumentContext,
Html,
Main,
NextScript,
Head,
} from "next/document";
import { ServerStyleSheet } from "styled-components";
export default class MyDocument extends Document {
static async getInitialProps(
ctx: DocumentContext
): Promise<DocumentInitialProps> {
const sheet = new ServerStyleSheet();
const originalRenderPage = ctx.renderPage;
try {
ctx.renderPage = () =>
originalRenderPage({
enhanceApp: (App) => (props) =>
sheet.collectStyles(<App {...props} />),
});
const initialProps = await Document.getInitialProps(ctx);
return {
...initialProps,
styles: [
<>
{initialProps.styles}
{sheet.getStyleElement()}
</>,
],
};
} finally {
sheet.seal();
}
}
render(): ReactElement {
return (
<Html lang="ko">
<Head></Head>
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
}
앱이 렌더링 될때, ServerStyleSheet를 생성하고, Context API를 통해 React tree에 스타일을 주입한다.
<Document/>는 Html, Head, Body등 모든 태그들을 감싸고, renderPage()를 통해 Server side에서 동기적으로 렌더를 하게된다.
js로 작성된 예시는 참고자료 StackOverFlow의 답변을 확인하면된다.
참고자료
https://medium.com/swlh/server-side-rendering-styled-components-with-nextjs-1db1353e915e
https://stackoverflow.com/questions/59672605/styled-components-delay-setting-property-in-nextjs
https://stackoverflow.com/questions/67087999/how-to-properly-type-the-document-tsx-file-from-next-js