본문 바로가기

Dot Programming/React ∙ Next.js

[Next.js] CSS(styled-components) 서버사이드 렌더링(SSR)

    Next.js CSS 경고 : Warning: Prop `className` did not match

    SEO최적화를 위해 Next로 SSR을 하는 경우 styled-components와 같은 CSS styling이 새로고침하는 경우 작동이 안되는 에러가 있다.

     

    이는 CSS가 SSR이 안되었기 때문인데,  console에 아래와 같은 warning이 발생한다. Warning: Prop `className` did not match

     

     

     

    CSS(styled-components) 서버사이드 렌더링(SSR)

    Next Babel 커스터마이징하기

    Next내부에도 Webpack과 Babel이 있는데 Babel을 커스터마이징해서 CSS를 SSR해주면 된다.

     

    1) babel-plugin-styled-components 설치

    $ npm i babel-plugin-styled-components

     

    2) project root에 파일 .babelrc생성

    {
        "preset": ["next/babel"],
        "plugins": [
            ["babel-plugin-styled-components", {
                "ssr": true,
                "displayName": true
            }]
        ]
    }

     

     

    3) /page/_documnent.js 생성 후 document 커스터마이징

    _documnent.js : styled-component를 SSR해주는 곳

    import Document, { Html, Head, Main, NextScript } from 'next/document'
    import React from 'react'
    import { ServerStyleSheet } from 'styled-components';
    
    
    export default class MyDocument extends Document{
        static async getInitialProps(ctx){
            const sheet = new ServerStyleSheet();
            const originalRenderPage = ctx.renderPage;
    
            try{
                //css를 ssr해주는 메소드
                ctx.renderPage = () => originalRenderPage({
                    enhanceApp: (App) => (props) => sheet.collectStyles(<App {...props} />),
                });
    
                const initialProps = await Document.getInitialProps(ctx);
                return {
                    ...initialProps,
                    styles: (
                        <>
                            {initialProps.styles}
                            {sheet.getStyleElement()}
                        </>
                    )
                };
            }catch(error){
                console.log(error);
            }finally{
                sheet.seal();
            }
        }
    
        render(){
            return(
                <Html>
                    <Head>
                        <body>
                            <Main />
                            <NextScript />
                        </body>
                    </Head>
                </Html>
            )
        }
    }

     

    IE에서 실행하면 라이브러리 버전이 너무 높아서 안돌아간다.

    최신문법 → babel로 바꾸면되는데 promise, map, set은 babel로 안된다.

     

    ☛ 그래서 polyfill.io를 script로 추가하기로 했다.

    (babel polyfill도 있지만 요즘 너무 무거워서 잘 사용하지 않음)

     

     

    위와 같이 체크해주고 _document.js의 <NextScript />위에 넣어주면 된다.

        render(){
            return(
                <Html>
                    <Head>
                        <body>
                            <Main />
                            <script src="https://polyfill.io/v3/polyfill.min.js?features=default%2Ces2015%2Ces2016%2Ces2017%2Ces2018%2Ces2019" />
                            <NextScript />
                        </body>
                    </Head>
                </Html>
            )
        }