프로그래밍/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