Don't think! Just do it!

종합 IT 기술 정체성 카오스 블로그! 이... 이곳은 어디지?

Next.js

Next.js + styled-components + tailwindcss + SSR

방피터 2022. 5. 28. 16:35

자 하나씩 순서대로 가자고~

 

next.js에 styled-components을 적용하는 건 그다지 어렵지 않아.

 

그냥 설치하고 

yarn add styled-components @types/styled-components

import해서 사용하면 끝.

import type { NextPage } from "next";
import styled from "styled-components";

const Title = styled.h1`
  color: yellowgreen;//글씨 색 yellow green으로!
`;

const Home: NextPage = () => {
  return (
    <div>
      <Title>Hello world</Title>
    </div>
  );
};

export default Home;

 

그런데 이렇게만 하면 처음 페이지가 로딩될 때 css가 적용되지 않아. javascript가 로딩되고 나서야 css가 적용돼. 이게 뭐가 문제가 되냐고? 페이지 로딩 속도가 늦거나 하면 css가 적용되지 않은 페이지(끔찍)만 주르륵 뜨겠지 ㅎㅎ 그러면 꼴보기 싫잖아? next.js server-side 랜더링 효과도 절반만 사용하는 것 같고

 

styled-components를 ssr(server-side randering)하고 싶어서 찾아보니 아래 코드처럼 _document.tsx를 구성하면 된다고 하네.

import Document, { DocumentContext } from "next/document";
import { ServerStyleSheet } from "styled-components";

export default class MyDocument extends Document {
  static async getInitialProps(ctx: DocumentContext) {
    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();
    }
  }
}

이렇게 하면 자바 스크립트 옵션을 꺼도 css가 적용된 페이지를 볼 수 있지.

javascript를 차단해도 css가 적용된다.

 

아마 next.js build할 때 html <head> tag 안에 style tag가 생성하나봐~ html 안에 있더라구.

<head> tag 안의 <style> tag

 

styled-component server-side randering 관련 자세한 설명은 아래 링크에 있으니 참고해

https://styled-components.com/docs/advanced#server-side-rendering

 

styled-components: Advanced Usage

Theming, refs, Security, Existing CSS, Tagged Template Literals, Server-Side Rendering and Style Objects

styled-components.com

 

(참고) next.config.js 파일에 styledComponents: true를 추가하면 된다고 나와 있는데 이건 뭐 아무 상관이 없는 거 같더라고.. 내가 뭔가 잘 못하고 있나? ㅠㅠ

/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
  //아래 추가하라고 하네~
  compiler: {
    styledComponents: true,
  },
};

module.exports = nextConfig;

그리고 다른 사람들이 styled-components에다가 tailwindcss까지 적용해서 사용들 하더라고 나도 괜찮겠다 싶어서 해봤지.

 

우선 tailwind를 ssr로 적용하는 방식이 tailwindcss-cli로 빌드한 css를 next.js _document.js에 삽입해서 next.js 빌드할 때 style에 때려박는 방식이야. 따로 빌드해주는 것 말고는 styled-components하고 거의 비슷해.

 

그럼 우선 tailwindcss 설치부터 해주자. 아래 링크에 아주 잘~ 나와 있음.

https://tailwindcss.com/docs/guides/nextjs

 

Install Tailwind CSS with Next.js - Tailwind CSS

Documentation for the Tailwind CSS framework.

tailwindcss.com

 

먼저 tailwindcss-cli랑 raw-loader 설치해주자.

yarn add -D tailwindcss-cli raw-loader

 

package.json 파일 scripts 옵션에다가 prebuild 추가해주고(아까 tailwindcss를 css로 build해서 때려 박는다고 그랬잖아 이거임)

"scripts": {
    "prebuild": "tailwindcss-cli build -o styles/tailwindSSR.css"
},

 

그리고 나서 next.js의 _document.js 파일에 빌드가 완료된 css파일을 import -> style 삽입.

import Document, { DocumentContext } from "next/document";
import { ServerStyleSheet } from "styled-components";

//@ts-ignore
import bundleCss from "!raw-loader!../styles/tailwindSSR.css";//빌드한거 import

export default class MyDocument extends Document {
  static async getInitialProps(ctx: DocumentContext) {
    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,
          ///////// 여기서부터 /////////
          <style
            key="custom"
            dangerouslySetInnerHTML={{
              __html: bundleCss,
            }}
          />,
          ///////// 여기까지 추가 ////////
          sheet.getStyleElement(),
        ],
      };
    } finally {
      sheet.seal();
    }
  }
}

 

이제 마지막으로 tailwind-styled-components 설치하고 사용해 보자규.

npm i tailwind-styled-components

 

index.js

import type { NextPage } from "next";
import styled from "styled-components";
import tw from "tailwind-styled-components";

const Title = styled.h1`//styled-components
  color: yellowgreen;
`;

const TitleTailwind = tw.h1`//tailwind-styled-components
  text-red-300
  text-xl
`;

const TitleTailwindStyledCombined = tw(Title)`//combined
  text-3xl
`;

const TitleStyledTailwindCombined = styled(TitleTailwind)`//combined
  color: blueviolet;
`;

const Home: NextPage = () => {
  return (
    <div>
      <Title>Hello styled-components</Title>
      <TitleTailwind>Hello Tailwind</TitleTailwind>
      <TitleTailwindStyledCombined>
        Hello Tailwind extends styled-components
      </TitleTailwindStyledCombined>
      <TitleStyledTailwindCombined>
        Hello styled-components extends Tailwind
      </TitleStyledTailwindCombined>
    </div>
  );
};

export default Home;

코드 보면 알겠지만 매우 자유롭게 사용이 가능해 ㅎ 어떤건 순수하게 styled-components로 사용하던지 tailwind가 적용된 styled-components로 사용해도 되고 또 서로를 extends해도 되지.

 

그런데 여기서 곧바로 yarn dev 해서 nextjs를 실행하면 모듈이 없다는 에러가 나와. 당연하겠지만 아직 build를 안해서 prebuild도 동작을 안했겠지? 그럼 _document.tsx 에서 import하려고 하는 tailwindSSR.css도 아직 없단 말이지. 그래서 에러가 발생해.

 

그래서 빌드 먼저 해보자구.

yarn build

 

그리고 나면 tailwindSSR.css라는 파일이 생성이 될거고 그 다음

yarn dev

 

그리고 브라우져에서 확인해보면 알록달록한 css가 적용된 모습을 볼수 있어. 물론 자바스크립트가 차단된 상태에서도 말이지.

nextjs에 styled-components + tailwindcss 적용된 모습

 

음.. 다 됐네? 뭐 까먹은거 없나? 설명 빼먹은게... 에이 잘 모르겠다 ㅎㅎ

 

암튼 이렇게 하면 styled-components랑 tailwindcss 동시에 사용이 가능하다는거~ 거기에 SSR도 된다는거 ㅎㅎ 매우 좋아!

 

여기에 마지막으로 tailwindcss 만 optimazation해서 사용하면 되겠다. 파일이 크니깐 말이지.

우선 package.json에서 prebuild에 --minify option 붙이고

"scripts": {
    "prebuild": "tailwindcss-cli build -o styles/tailwindSSR.css --minify",
    ...
}

 

postcss.config.js에 아래 코드처럼 cssnano 추가해주면 마무으리~

module.exports = {
  plugins: {
    tailwindcss: {},
    autoprefixer: {},
    ...(process.env.NODE_ENV === 'production' ? { cssnano: {} } : {})
  }
}

 

얼마나 크기가 줄어드는 지는 잘 모르겠는데 tailwindcss에서는 보통 10kb 이내로 줄어든다고 그래 -> 아래 링크~

https://tailwindcss.com/docs/optimizing-for-production

 

Optimizing for Production - Tailwind CSS

Getting the most performance out of Tailwind CSS projects.

tailwindcss.com

반응형

'Next.js' 카테고리의 다른 글

Next.JS 프로젝트 기본 템플릿 만들기#1  (0) 2022.06.14
Next.js NextUI  (0) 2022.06.08
Next.JS App engine 비용  (0) 2022.05.26
Next.JS Font optimization(웹 폰트 삽입 위치)  (0) 2022.05.25
Next.JS on Google Cloud App engine  (0) 2022.05.23