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
'프로그래밍 > JS, Node.js' 카테고리의 다른 글
CloudFlare KV로 앱 점검시간 관리하기 (1) | 2023.01.21 |
---|---|
[typescript] 어두운 색깔인지 확인 (isDarkColor, HEX, RGB, tinycolor) (0) | 2022.08.14 |
[Next.js] next/image 이미지 로딩이 너무 느릴때 (0) | 2022.08.05 |
[Next.js] MongoDB 연결하기 (next-connect, typescript) (0) | 2022.06.26 |
[Next.js] 개발 모드에서 useEffect가 두 번 호출될때 (0) | 2022.06.25 |