storybook 실행 시 Could not resolve "@emotion/react" 에러 해결 (feat. storybook, vite, styled-components, viteFinal)

보투게더·2023년 10월 10일
1

트러블슈팅

목록 보기
1/1

Could not resolve "@emotion/react"

디자인 시스템 구현을 위해 storybook으로 테스트해보기 위해 npm run storybook 실행을 해보니, 아래와 같은 오류가 떴습니다...

X [ERROR] Could not resolve "@emotion/react"

    ../../node_modules/@emotion/styled/dist/emotion-styled.browser.esm.js:5:7:
      5 │ import '@emotion/react';
        ╵        ~~~~~~~~~~~~~~~~

  You can mark the path "@emotion/react" as external to exclude it from the bundle, which will       
  remove this error.

X [ERROR] Could not resolve "@emotion/react"

    ../../node_modules/@emotion/styled/base/dist/emotion-styled-base.browser.esm.js:4:47:
      4 │ import { withEmotionCache, ThemeContext } from '@emotion/react';
        ╵                                                ~~~~~~~~~~~~~~~~

보투게더 디자인 시스템 프로젝트에서 기술 스택은, Vite(React+TypeScript), Storybook(v7.4.6), styled-components(v6.0.8)으로 구성되어 있습니다.

emotion을 쓰지도 않는데(styled-components로 스타일링하는데..) 정말 뚱딴지 같은 오류가 발생한 것이었습니다...🤔🤔😂

별도로 emotion 패키지를 설치한 것이 하나도 없었기에, storybook에서 emotion을 사용하는 것으로 추정됩니다.

package-lock.json을 확인해보자!

package-lock.json 을 열어보니 storybook에서 emotion의 일부 패키지를 사용하고 있었습니다.

뿐만 아니라 styled-components 에서도 emotion을 dependencies로 사용하고 있었다.

그렇다는 것은 storybook이나 styled-components의 문제인 것인데... styled-components 로 스타일링하는 코드에서 별다른 오류가 없었던 것으로 짐작컨대, storybook에서 emotion 관련 오류가 일어나는 것 같았습니다.

storybook 과 emotion 충돌

완전히 동일한 오류는 아니었지만, 한 블로그 글storybook의 Issue에서 이와 유사한 상황을 발견하였다.
두 가지 모두 emotion 버전과 storybook 버전이 충돌하는 상황이었다.

해결 방법

우리 프로젝트의 vite로 구성했기 때문에, storybook 역시 vite로 빌드되도록 하였습니다.

기존 .storybook/main.ts

import type { StorybookConfig } from "@storybook/react-vite";

const config: StorybookConfig = {
  stories: ["../src/**/*.mdx", "../src/**/*.stories.@(js|jsx|mjs|ts|tsx)"],
  addons: [
    "@storybook/addon-links",
    "@storybook/addon-essentials",
    "@storybook/addon-onboarding",
    "@storybook/addon-interactions",
  ],
  framework: {
    name: "@storybook/react-vite",
    options: {},
  },
  docs: {
    autodocs: "tag",
  },
};
export default config;

블로그 글과 storybook issue 글처럼 webpackFinal 속성을 Storybook Config로 추가하려 했는데, 아예 잘못된 코드라고 빨간 줄이 떴습니다..

그런데 생각해보니 우리 프로젝트는 vite 번들러를 사용하기 때문에, webpackFinal 이 아닌 viteFinal을 사용해야 했습니다. (헉..~😂😂💡)

에러 해결을 위해 수정한 결과

아래 코드와 같이 viteFinal 속성을 추가해주자!

import type { StorybookConfig } from '@storybook/react-vite';

const path = require('path');

const resolvePath = (_path) => path.join(process.cwd(), _path);

const config: StorybookConfig = {
  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],
  addons: [
    '@storybook/addon-links',
    '@storybook/addon-essentials',
    '@storybook/addon-onboarding',
    '@storybook/addon-interactions',
  ],
  framework: {
    name: '@storybook/react-vite',
    options: {},
  },
  docs: {
    autodocs: 'tag',
  },
  viteFinal: async (config) => ({
    ...config,
    resolve: {
      ...config.resolve,
      alias: {
        ...config.resolve?.alias,
        '@emotion/core': resolvePath('node_modules/@emotion/react'),
        '@emotion/styled': resolvePath('node_modules/@emotion/styled'),
        'emotion-theming': resolvePath('node_modules/@emotion/react'),
      }, // 이거(emotion-theming)는 없어도 무방함
    },
  }),
};
export default config;

🤔 viteFinal 이란?

(아래는 gpt의 답변을 참고하였습니다.)
.storybook/main.ts 파일에서 viteFinal 함수를 정의한 부분은, Vite 설정을 변경하거나 확장하기 위한 옵션입니다. 이 옵션에서 해당 함수는 비동기 함수로 작성되어야 하고, 이 함수는 Vite의 설정 객체를 입력으로 받아 해당 설정을 변경하고 반환해야 합니다. 여기서 주요한 부분은 resolve 객체의 alias 설정을 변경하는 부분입니다. alias 설정을 통해 모듈을 더 쉽게 import하고 경로를 해석할 수 있습니다.

예를 들어, @emotion/core, @emotion/styled, 그리고 emotion-theming 모듈의 경로를 node_modules 디렉토리 내에서 직접 지정함으로써 해당 모듈을 import할 때 상대 경로를 사용하는 대신 이러한 별칭을 사용하여 모듈을 import할 수 있게 됩니다. 이렇게 설정을 변경함으로써 Vite는 이러한 모듈을 제대로 해석하고, import할 때 경로 문제를 해결할 수 있게 됩니다.

즉, viteFinal 함수를 사용하여 Storybook에서 Vite의 설정을 수정하고 특정 모듈의 경로를 재정의하고 있습니다. 이렇게 함으로써 Storybook과 Vite를 함께 사용할 때 원활한 모듈 해석 및 빌드를 지원합니다.

검색해도 완벽하게 일치하는 키워드가 없어서 에러 해결에 2-3시간을 소비했지만... 어쨌든 해결했으니 만족스럽습니다👏👏👍

📚참고자료

https://xo.dev/articles/fix-storybook-emotion-11-error

profile
Fun from Choice! 오늘도 즐거운 한 표

1개의 댓글

comment-user-thumbnail
2023년 10월 23일

정보 감사해용 👍👍👍

답글 달기