디자인 시스템 구현을 위해 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 을 열어보니 storybook에서 emotion의 일부 패키지를 사용하고 있었습니다.
뿐만 아니라 styled-components 에서도 emotion을 dependencies로 사용하고 있었다.
그렇다는 것은 storybook이나 styled-components의 문제인 것인데... styled-components 로 스타일링하는 코드에서 별다른 오류가 없었던 것으로 짐작컨대, 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;
(아래는 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시간을 소비했지만... 어쨌든 해결했으니 만족스럽습니다👏👏👍
정보 감사해용 👍👍👍