Next.js 14와 Storybook에서 TailwindCSS를 함께 사용하기 위한 호환성 문제 및 해결 방법
(추가 2024. 10) 2024년 10월 기준으로 Next.js 14.2.15, Storybook 9.3.5, TailwindCSS 3.4.14 조합에서는 TailwindCSS가 정상적으로 동작하는 것이 확인되었습니다. 이로써 최신 Storybook에서의 호환성 문제를 해결하고, TailwindCSS를 활용한 디자인 시스템 구축이 원활히 이루어질 수 있습니다.
개발자들에게는 버전 호환성을 주의 깊게 확인하는 것이 중요하며, 최신 버전의 안정성을 보장받기 전까지는 이전 버전을 사용하는 것이 안정적일 수 있습니다.
(추가 2024. 07) Storybook 최신 버전 8을 TailiwdCSS와 연동하여 사용하는 경우 tailwind가 적용이 안되는 이슈가 있습니다. Storybook 깃 레포의 이슈탭에는 아직도 여전히 처리가 되지 않고 있다. stable release가 3월에 되었지만 최초 버그가 제기된 이후로 여전히 해결이 되지 않고 있어 최신 Storybook에서 사용이 안되고 있습니다.
최근 프로젝트에서 Next.js 14, Tailwind CSS와 Storybook을 결합하여 디자인 시스템을 구축하려는 시도를 했습니다. 그러나 Storybook의 최신 버전(8.x)을 사용했을 때 Tailwind CSS가 제대로 동작하지 않는 문제가 발생했습니다. 많은 개발자들이 이와 같은 호환성 문제를 겪고 있으며, 이에 대한 해결 방법을 공유하려 합니다.
1. 문제 개요 - Storybook 최신 버전 8.X의 호환성 문제
Storybook은 독립적으로 컴포넌트를 개발하고 테스트하는 강력한 도구입니다. 그러나 최신 버전 8.x에서 Next.js 14와 TailwindCSS를 결합한 프로젝트에서 스타일(CSS)이 제대로 적용되지 않는 문제가 발생하고 있습니다.
이는 Tailwind의 테마 관련 CSS가 Storybook에서 렌더링되지 않아서 발생하며, PostCSS 처리 방식의 충돌이나 Webpack 설정 문제로 인해 스타일이 깨지거나 적용되지 않는 상황이 발생합니다. 안정적인 사용을 위해서는 Storybook 버전 7.6.17으로의 다운그레이드가 권장되지만, 최신 기능을 유지하고자 한다면 설정 조정을 통해 호환성을 맞출 수 있습니다.
2. 문제의 원인 분석
스토리북 깃허브 이슈에서 언급된 주요 문제는 다음과 같습니다:
2.1. PostCSS 설정 파일의 확장자 문제: 프로젝트에서 사용되는 postcss.config.mjs 파일이 Storybook의 **postcss-loader**에서 처리되지 않는 상황이 발생할 수 있습니다. 이는 Storybook의 빌드 시스템이 .mjs 파일을 자동으로 인식하지 못하기 때문에 발생합니다.
2.2. 글로벌 CSS 로딩 문제: TailwindCSS의 스타일은 globals.css 파일에 정의되어 있으며, 이 파일이 Storybook의 구성에서 제대로 로딩되지 않으면 스타일 적용이 되지 않습니다. 따라서 이 파일을 명시적으로 Storybook에 로드해야 합니다.
2.3. Webpack 설정 문제: Storybook에서 Next.js의 기본 Webpack 설정과 충돌이 발생할 수 있습니다. 이로 인해 TailwindCSS의 설정이 Storybook 내에서 적용되지 않거나 예기치 않은 빌드 오류가 발생할 수 있습니다.
3. 해결 방안
3.1. PostCSS 설정 파일 수정
TailwindCSS는 PostCSS를 통해 스타일을 처리합니다. 그러나 Storybook의 Webpack은 .mjs 확장자를 가진 PostCSS 설정 파일을 기본적으로 인식하지 않기 때문에, 이를 해결하기 위해 설정 파일의 확장자를 변경해야 합니다.
postcss.config.mjs → postcss.config.cjs
이렇게 확장자를 .cjs로 변경하면, CommonJS 모듈 형식을 사용하는 설정 파일로 인식되어 Storybook과 더 호환성이 좋습니다. 이 변경으로 Storybook에서 PostCSS 설정을 올바르게 로드할 수 있습니다.
3.2. tsconfig.json 수정
TypeScript 설정 파일인 **tsconfig.json**에서 모듈 경로를 업데이트하여 새롭게 변경된 설정 파일을 포함시켜야 합니다. 다음과 같이 "include" 항목에 **/*.cjs를 추가합니다. 이를 통해 TypeScript가 새로 추가된 .cjs 파일을 빌드 과정에서 고려할 수 있도록 합니다.
{
"include": [
"**/*.ts",
"**/*.tsx",
"**/*.cjs"
]
}
3.3. 글로벌 CSS 파일 Storybook에 로드
TailwindCSS 스타일이 정의된 globals.css 파일을 Storybook에서 명시적으로 불러와야 합니다. 이를 위해 Storybook의 설정 파일에서 globals.css 파일을 import해야 합니다. 다음은 preview.ts 파일의 수정 예시입니다.
// .storybook/preview.ts
import type { Preview } from "@storybook/react";
import "../src/app/styles/globals.css";
const preview: Preview = {
parameters: {
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/i,
},
},
},
};
export default preview;
위 코드에서 ../src/app/styles/globals.css 파일을 import 함으로써, TailwindCSS의 스타일을 Storybook에서도 동일하게 사용할 수 있습니다. 이 설정이 없다면 Storybook에서 TailwindCSS 스타일이 적용되지 않거나 일부 컴포넌트가 잘못 표시될 수 있습니다.
3.4. Webpack 설정 수정
Storybook은 기본적으로 Webpack 5를 사용하고 있으며, Next.js의 Webpack 설정과 통합되어야 합니다. TailwindCSS가 Storybook에서 정상적으로 작동하지 않는다면, Storybook의 Webpack 설정을 커스터마이징하여 PostCSS와 TailwindCSS 로더를 추가해야 할 수 있습니다.
(참고 : tailwind 3 doesn't work with storybook/webpack setup)
이 설정을 통해 Webpack에서 TailwindCSS와 PostCSS 설정을 제대로 인식하게 하고, 모든 CSS 파일에 대해 TailwindCSS 유틸리티를 사용할 수 있게 합니다.
module.exports = {
stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'],
addons: [
'@storybook/addon-links',
'@storybook/addon-essentials',
'@storybook/addon-interactions',
],
framework: '@storybook/react',
webpackFinal: async (config) => {
// TailwindCSS와 PostCSS를 위한 로더 추가
config.module.rules.push({
test: /\.css$/,
use: [
'style-loader',
'css-loader',
{
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: [
require('tailwindcss'),
require('autoprefixer'),
],
},
},
},
],
include: path.resolve(__dirname, '../'),
});
return config;
},
};
4. 추가 팁: TailwindCSS와 Storybook의 통합 유지
4.1. TailwindCSS Config 확장: TailwindCSS의 설정 파일(tailwind.config.ts)에서 Storybook에서 사용할 추가적인 콘텐츠 경로를 지정하여, Storybook 내의 컴포넌트들이 TailwindCSS의 스타일을 제대로 사용하게 할 수 있습니다.
content 속성은 TailwindCSS가 적용될 파일 경로를 지정하는 속성입니다. TailiwindCSS는 이 경로들을 기준으로 사용자가 사용하고 있는 클래스 이름을 찾고, 해당 클래스들만 포함하여 최종 CSS 파일을 생성합니다.
import type { Config } from "tailwindcss";
const config: Config = {
content: [
"./app/**/*.{js,ts,jsx,tsx,mdx}",
"./pages/**/*.{js,ts,jsx,tsx,mdx}",
"./components/**/*.{js,ts,jsx,tsx,mdx}",
// Or if using `src` directory:
"./src/**/*.{js,ts,jsx,tsx,mdx}",
],
theme: {
extend: {
colors: {
"gray-25": "rgba(251, 251, 251, 1)",
Storybook에서 TailwindCSS를 올바르게 적용하기 위해서는 프로젝트의 글로벌 스타일인 styles/globals.css가 Storybook에서도 적용될 수 있도록 설정하는 것이 중요합니다.
글로벌 CSS는 Next.js의 app 폴더에 포함되어 있으며, 이 스타일을 Storybook의 Storybook UI 환경에서도 동일하게 사용해야 합니다. 이를 위해 스토리북에서 사용하는 컴포넌트를 모아놓은 stories 폴더 역시 app 폴더의 구조에 포함시켜, TailwindCSS와 글로벌 스타일이 Storybook의 각 컴포넌트에 동일하게 적용될 수 있도록 구성합니다.
이렇게 함으로써 TailwindCSS 유틸리티 클래스와 글로벌 스타일을 Storybook 내에서 렌더링할 때도 동일하게 적용할 수 있게 되어, 디자인 시스템과 컴포넌트 간의 스타일 일관성을 유지할 수 있습니다. 이 작업은 Storybook과 실제 애플리케이션 간의 시각적 차이를 줄이고, Storybook에서 개발 중인 컴포넌트들이 실제 제품에서 사용될 때와 동일한 스타일을 보장할 수 있게 합니다.
4.2. Addon 사용: Storybook에서 TailwindCSS를 더 쉽게 사용할 수 있도록 하는 TailwindCSS Addon을 사용해보는 것도 좋은 방법입니다. 이는 설정 작업을 줄여주고, Storybook 환경에서 TailwindCSS 유틸리티 클래스를 보다 효과적으로 사용할 수 있도록 도와줍니다.
5. 결론
Storybook과 TailwindCSS를 Next.js 프로젝트에서 함께 사용할 때 발생하는 문제는 대부분 설정 파일의 인식 문제나 Webpack 설정의 불일치에서 발생합니다. 이 문제를 해결하기 위해 다음과 같은 조치를 취할 수 있습니다.
5.1. PostCSS 설정 파일의 확장자를 .cjs로 변경하여 호환성을 높입니다.
5.2. 글로벌 CSS 파일을 Storybook에 명시적으로 로드하여 TailwindCSS 스타일이 모든 컴포넌트에 적용되도록 합니다.
5.3. Webpack 설정을 커스터마이징하여 TailwindCSS와 PostCSS 로더를 추가합니다.
5.4. TailwindCSS 설정에서 Storybook 관련 콘텐츠 경로를 지정하여 스타일이 올바르게 적용되도록 합니다.
이러한 설정을 통해 Storybook과 TailwindCSS 간의 호환성을 개선하고, Storybook 내에서 컴포넌트를 TailwindCSS 스타일과 함께 정확하게 테스트할 수 있습니다.