[Next + TypeScript] 넥스트 프로젝트에 Material UI + styled-components 적용하기 (emotion 씁시다)

퍼렁꽁치·2022년 3월 29일
4

나는 개인적으로 여러 UI 라이브러리 중에 Material UI (이하 MUI)를 선호하고 있다. 개인적으로 ant design 이나 부트스트랩보다 디자인이 깔끔하고 사용하기도 편한 것 같다
그리고 MUI 와 함께 사용하는 것이 styled-components다.

먼저 Next 프로젝트를 이미 시작해서 열려있는 것을 가정하겠다.

1. Material UI 설치하기

어떤 라이브러리를 사용할 때 가장 좋은 점은 공식문서를 바로 확인하는 것이다.

MUI 는 기본적으로 emotionstyled-components 친화적이랄까, 둘 중 어떤 것을 선택할지 두 개의 선택지를 제공하고 있다.
이 중에 원하는 것을 선택해서 위에 적힌 CLI 명령어 대로 설치해주면 된다.

개인적인 이유지만, 나는 styled-components 로 하다가 모종의 이유로 MUI 에서 쓸 때는 emotion 을 쓰고 있다. 그 이유에 대해서는 아래에서 명시하겠다. 일단 styled-components 로 프로젝트를 진행하겠다면 이 중 아래의 선택지를 선택하면 된다.

// with npm
npm install @mui/material @mui/styled-engine-sc styled-components

// with yarn
yarn add @mui/material @mui/styled-engine-sc styled-components

잠깐 타입스크립트 유저여..

// with npm
npm install @types/styled-components

// with yarn
yarn add @types/styled-components

프로젝트에서 타입스크립트를 쓴다면 추가로 @types/styled-components 를 함께 다운받아 주어야 한다.
패키지 앞에 @types/... 가 붙은 것은 타입스크립트를 지원하지 않는 패키지에 해당 패키지의 타입을 읽을 수 있도록 작성된 일종의 추가템이다. 타입스크립트를 지원하는 라이브러리는 보통 해당 라이브러리를 설치하는 것만으로도 해결이 되지만, 종종 이렇게 지원하지 않는 라이브러리는 앞에 @types/라이브러리명을 찾아보면 된다.

추가로 Material UI 에서 제공하는 아이콘들을 쓰겠다면

// with npm
npm install @mui/icons-material

// with yarn
yarn add @mui/icons-material

MUI 에서는 자체적으로 아이콘들도 제공하고 있다. 아이콘의 경우는 다양한 경로로 아이콘을 찾아 쓸 수 있지만, 간단한 사이드 프로젝트에서 MUI 에서 제공하는 걸로 한번에 해결하고 싶다면 MUI 것을 쓰는 것도 나쁘지 않다. 생각보다 다양한 아이콘들을 지원하고 있어서 생각보다 쓸만하다.
MUI 에서 제공하는 아이콘들을 쓰겠다면 위의 명령어를 추가로 적어주면 된다.

2. babel-plugin 설치

결정적으로 이 부분이 내가 styled-components 에서 emotion 으로 갈아탄 이유다.
사실 정확히 어떤 이유라고 설명할 만큼 잘 아는 것은 아니지만, 넥스트 환경에서 styled-components 가 제대로 적용이 안 되는 문제가 발생하곤 한다.

이걸 파악한 것은 이전에 제로초님의 노드버드 강의를 들을 때 발견했는데,
NextJS 는 기본적으로 서버사이드 환경에서 미리 렌더링을 해놓는 시스템인데, SSR(서버사이드 렌더링)시에 styled-components 가 함께 적용이 되어야 하는데 적용이 안됨으로써 스타일이 서버사이드에서 안 먹는 문제였다.
아마도 styled-components 또한 CSS-in-JS 로서 기본적으로 '자바스크립트'이기 때문에 자바스크립트가 동작하지 않는 서버사이드 환경에서 그런 문제가 발생한 것이 아닐까 싶다.

때문에 넥스트에서 styled-components 를 쓰기 위해선 이처럼 추가 설정을 해주어야 하고, 놀랍게도 emotion 에서는 이와 같은 설정을 해주지 않아도 동작한다!!
그런 이유로 지금 진행하고 있는 프로젝트에서는 emotion 을 쓰고 있다. 아무튼 이 글은 넥스트에서 styled-components 를 적용하는 글이기 때문에 이어서 작성해보겠다.

1) .babelrc 설정

// with npm 
npm install @babel-plugin-styled-components --save-dev

// width yarn 
yarn add @babel-plugin-styled-components --dev

먼저 @babel-plugin-styled-components 를 설치해준다.

그 다음에는 루트디렉토리에 .babelrc 파일을 생성해준다.

// .babelrc
{
	"presets": ["next/babel"],
  	"plugins": [
    	["styled-components", { "ssr": true }]
    ]
}

위에처럼 코드를 작성해준다.
대강 읽어보면 감이 오겠지만 styled-components 에 대해 SSR 을 true 로 해준다는 내용 같다.

2) _document.tsx 파일 작성

넥스트로 프로젝트를 열면 _app.tsx 는 보이는데 _document.tsx 파일은 안 보일 것이다.
둘의 차이를 간략하게 짚어보고 가자면,
1) _app.tsx 는 해당 컴포넌트에서 '렌더링'하는 것은 모든 페이지에 영향을 준다. 때문에 공통적인 레이아웃을 줄 때 주로 사용하며
2) document.tsx 는 meta태그를 정의하는 등, static 한 상황에서만 사용한다.

지금은 대충 그런가보다 하고 넘어가고 pages/ 디렉토리에 _app.tsx 파일이 있는 디렉토리에 나란히 _document.tsx 를 생성한다.

// _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()
    }
  }
}

이 코드에 대해 정확히 이해하는 것은 아니지만, 아무튼!!! 이 코드를 그대로 복사 붙여넣기 해주면 된다.
그러면 전체적인 styled-components 설정은 끝나고 서버사이드에서도 styled-components 가 적용이 되는 것을 볼 수 있다.

추가로...

MUI 를 쓰면서 가장 상단에서 emotionstyled-components 중 선택해서 패키지를 설치해 진행할 수 있다고 했다.
그런데 나는 이전 미니 프로젝트에선 styled-components 로 진행하다가 현재 프로젝트에서는 emotion 으로 진행하고 있다.

emotionstyled-components 는 닮은 부분이 많다. 그럼에도 emotion 이 나온 이유는 styled-components 의 여러점을 개선하고자 나온 것이 아닐까.
내가 styled-components 에서 emotion 으로 갈아탄 이유는 아래와 같다.

1) 타입스크립트 지원

  • styled-components 에서는 타입스크립트를 미지원하기 때문에 @types/styled-components 를 추가로 설치해야 했지만 emotion 의 경우 자체에서 타입스크립트를 지원하기 때문에 추가로 설치할 필요가 없다.

2) 위의 '2) _document.tsx 파일 작성' 같은 추가적인 코드를 작성할 필요가 없다.

  • 내가 알고서 활용한다면 전혀 문제될 점은 없다. 그러나 저 2)번의 코드는 현재의 나로서는 이해하기가 다소 힘들다. 그런데 내 코드상에 내가 이해하지 못하는 코드가 있다는 점이 내 스스로는 아이러니했다. 오히려 저런 코드마저 불필요한 emotion 으로 갈아타지 않을 수 없는 결정적 이유였다.

3) MUI 에서 styled-components 로 해도 결국 emotion 을 다운받는다?

  • 이 이유는 정확히 나만 그런건지, 모두가 그런건지는 모르겠다. 나의 경우 styled-components 로 선택했음에도 중간에 에러 문구를 보면 emotion 관련 패키지를 찾지 못해 페이지를 열지 못하는 문제가 발생했다. 때문에 추가로 emotion 관련 패키지를 설치해야했다.
  • 그래서 그 다음에 진행한 현재 프로젝트에서는 애초에 emotion 으로 프로젝트를 진행하자 그런 불필요하게 emotion 관련 패키지를 설치하란 문구가 없었다. 왜? 이미 emotion 으로 진행하고 있으니깐!!!

이상 넥스트에서 MUI 와 styled-components 를 적용하는 방법에 대해 글을 써봤다.
MUI 는 뒷전이고 사실은 styled-components 를 적용하는 방법에 대한 글이었다.
하지만 결론은... 적어도 MUI 에선 styled-components 보다는 emotion 을 쓰는 것이 보다 좋지 않을까 하는 것이 결론이다.

profile
무엇이든 될 수 있는 멋쟁이 토마토🍅 프론트 꿈나무💙

0개의 댓글