TIL 68 | Nextjs + typescript + Styled-components setting

ym j·2021년 10월 15일
0

NEXT

목록 보기
3/3
post-thumbnail

Nextjs + typescript + Styled-components setting

styled-components 관련 라이브러리 설치

yarn add styled-components styled-reset @types/styled-components babel-plugin-styled-components
  • 필요에 따라 styled-reset 혹은 styled-normalize를 설치할 수 있다.
  • styled-components, @types/styled-components, babel-plugin-styled-components를 설치한다.


styled.d.ts 파일 설정

// theme.ts (내부 스타일 요소는 예시입니다.)
import "styled-components";
//
declare module "styled-components" {
  export interface DefaultTheme {
    flex: (direction: string, justify: string, align: string) => string;
    //
    colors: {
      black: string;
      white: string;
    };
  }
}
  • 공유 스타일인 theme 파일의 인터페이스 타입을 styled-component의 모듈로 지정해준 후 export 한다.


theme.ts 파일 설정

// theme.ts (내부 스타일 요소는 예시입니다.)
import { DefaultTheme } from "styled-components";
//
const flex = (direction = "row", justify = "center", align = "center") => {
  return `
  display: flex;
  justify-content: ${justify};
  align-items: ${align};
  flex-direction: ${direction};
  `;
};
//
const colors = {
  black: "#0E0E0E",
  white: "#000000",
};
//
const theme: DefaultTheme = {
  flex,
  colors,
};
//
export default theme;
  • styled.d.ts 파일에서 exportDefaultThemetheme의 타입을 지정한다.


GlobalStyle.ts 파일 설정

//GlobalStyle.ts (내부 스타일 요소는 예시입니다.)
import { createGlobalStyle } from "styled-components";
import { reset } from "styled-reset";
//
const GlobalStyle = createGlobalStyle`
${reset}
  * {
    box-sizing: border-box;
  }
`;
  • 전역 스타일은 이전에 react with js에서 사용했던 방식과 동일하게 지정해준다.


root 경로에 .babelrc 파일 설정

// .babelrc
{
  "presets": ["next/babel"],
  "plugins": [
    [
      "styled-components",
      { "ssr": true, "displayName": true, "preprocess": false }
    ]
  ]
}
  • Nextjs는 최초 SSR 이후 부분적으로 CSR(클라이언트 사이드 렌더링)을 하게 되는데, 이때 server에서 생성되는 class 해시값과 client에서 생성하는 class 해시값이 달라 충돌로 인해 문제가 발생한다. 때문에 babel-plugin-styled-components.babelrc 파일을 설정하도록 하자. (설치 및 파일을 설정했음에도 계속 위와 같은 에러가 발생하다가 npm install을 통해 전체 모듈을 설치해주니 다시 정상적으로 제기능을 하였다.)


_document.js 파일 생성

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();
    }
  }
}
  • Next.js는 Pre-rendering을 통해 Initial load 과정에서 미리 HTML, CSS 등 정적인 요소들을 먼저 렌더링 한 후 JS 파일을 로드하며 Hydration이 이루어진다.

  • 위와 같은 이유로 인해 css-in-js의 경우, 스타일 요소 또한 늦게 로딩이 된다. (내 경우 아예 로드가 되지 않았다 .. 왜 그런지 이유는 못찾았음..) 이러한 문제점은 next.js 공식문서에서 제공하는 renderPage를 통해 해결할 수 있다. 즉, index.html 파일에 css-in-js 형식으로 작성된 스타일 요소들을 주입시켜줌으로써 스타일이 뒤늦게 적용되는 문제를 해결할 수 있다.

  • styled-component 공식문서 에서는 심지어 코드 샘플을 예제로 제공하고 있으며, 적용을 통해 정상적으로 스타일링이 HTML 요소에 적용됨을 확인할 수 있었다.



_app.js에 import

// _app.tsx
import type { AppProps } from "next/app";
//
import theme from "../src/styles/theme";
import { ThemeProvider } from "styled-components";
import { GlobalStyle } from "../src/styles/GlobalStyles";
//
export default function MyApp({ Component, pageProps }: AppProps) {
  return (
    <ThemeProvider theme={theme}>
      <GlobalStyle />
      <Component {...pageProps} />
    </ThemeProvider>
  );
}


Reference

profile
블로그를 이전하였습니다 => "https://jymini.tistory.com"

0개의 댓글