프로그래밍/JS, Node.js

[Next.js] styled-components를 Client side 렌더링 이전에 적용시키기 (덜그덕 방지, Typescript)

Lou Park 2022. 8. 5. 01:50

적용전, 처음 로딩시 CSS가 적용되지 않은채 시작되는 모습

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