junglast
Published on

React의 새로운 JSX Transform 환경에서 Emotion CSS prop 사용 설정하기

React 16.14.0 이후 도입된 새로운 JSX Transform 환경에서 css-in-js 라이브러리 Emotion의 css prop을 사용할 수 있도록 설정하는 방법입니다. 새 JSX Transform이 도입된 지 오랜 시간이 지나지 않았기도 하고, 이전 버전 React 기준으로 작성되어 있는 자료가 많아 다소 혼동이 되는 경우가 있었습니다.


Babel 설정을 수정할 수 있는 경우

Babel 설정을 직접 수정할 수 있는 경우는 아래와 같이 설정하면 됩니다.

{
  "presets": [
    ["@babel/preset-react", { "runtime": "automatic", "importSource": "@emotion/react" }]
  ],
  "plugins": ["@emotion/babel-plugin"]
}

Next에서는 아래와 같이 설정해야 합니다.

{
  "presets": [
    [
      "next/babel",
      {
        "preset-react": {
          "runtime": "automatic",
          "importSource": "@emotion/react"
        }
      }
    ]
  ],
  "plugins": ["@emotion/babel-plugin"]
}

Babel 설정을 수정할 수 없는 경우/하고 싶지 않은 경우

Babel 설정을 수정하지 않고 CSS Prop을 사용하려면 .jsx/.tsx 파일 최상단에 /** @jsxImportSource @emotion/react */ pragma를 설정하면 됩니다.

참고

  • 위처럼 @emotion/react를 import하면 Emotion 공식 문서나 여러 자료에서 언급되는 @emotion/babel-preset-css-prop은 새 JSX Transform에서는 더 이상 필요가 없습니다.
  • css prop을 사용하지 않을 예정이라면 위와 같은 설정이 필요 없습니다.

어떻게 작동하는가?

React 블로그에 따르면 새 JSX Transform 런타임은 JSX 코드를 아래와 같이 변환합니다.

import { jsx as _jsx } from "react/jsx-runtime"

function App() {
  return _jsx("h1", { children: "Hello world" })
}

위 코드에서는 react/jsx-runtime이 JSX Transform 런타임의 진입점(Entry point)이 됩니다.

한편, Emotion의 React 전용 라이브러리인 @react/emotion의 내부 코드를 살펴보면

var ReactJSXRuntime = require("react/jsx-runtime"),
  Fragment = ReactJSXRuntime.Fragment

function jsx(type, props, key) {
  return emotionElement.hasOwnProperty.call(props, "css")
    ? ReactJSXRuntime.jsx(
        emotionElement.Emotion,
        emotionElement.createEmotionProps(type, props),
        key
      )
    : ReactJSXRuntime.jsx(type, props, key)
}

function jsxs(type, props, key) {
  return emotionElement.hasOwnProperty.call(props, "css")
    ? ReactJSXRuntime.jsxs(
        emotionElement.Emotion,
        emotionElement.createEmotionProps(type, props),
        key
      )
    : ReactJSXRuntime.jsxs(type, props, key)
}

컴포넌트에 css prop이 있을 경우 이를 컴파일 할 수 있도록 기존 ReactJSXRuntime을 확장하고 있습니다. 상단에 언급한 바벨 설정에서 importSource의 값을 바꾸는 이유도 결국 React에서 제공하는 JSX 컴파일러를 Emotion의 JSX 컴파일러로 지정하기 위함일 것입니다. 따라서 @emotion/babel-preset-css-prop 없이 css prop을 바로 사용할 수 있게 됩니다.

타입스크립트 설정

tsconfig.json에 아래와 같은 옵션을 추가해 Emotion의 jsx runtime을 인식할 수 있도록 설정하면 됩니다.

{
  "compilerOptions": {
    ...
    "jsxImportSource": "@emotion/react",
    ...
  },
  ...
}

Next.js 12 이후에서 생기는 작은 문제

Next가 버전 12로 업데이트 되면서 Rust 기반의 자체 컴파일러를 도입했습니다. 이 컴파일러는 Babel을 대체하는 것이므로, 바벨 설정을 위해 .babelrc를 수정하면 다시 새 컴파일러 대신 Babel을 사용하게 됩니다. 따라서 Emotion 뿐만 아니라 별도의 Babel 설정이 필요한 라이브러리들을 사용하는 데에 이슈가 생기게 되는데, Next 측에서는 이러한 라이브러리들이 Rust 컴파일러에서도 실행될 수 있도록 별도의 작업을 진행 중이라고 합니다.