개발

Next.js, Vanilla extract 프로젝트에서 storybook 설정하기

배우겠습니다 2024. 3. 30. 18:38

개요

  • RSC에서 css in js를 사용하려면 결국 build time css in js를 활용해야한다.
  • 이중 vanilla extract가 대안이 될 수 있다.
  • vite와 달리 storybook 설정에 여러가지가 필요하다.
  • typescript next14 storybook8을 사용중인 프로젝트를 가정한다.

storybook

  • 번들링은 webpack기반이다.
  • addon 설정뿐만아니라 직접 webpack 설정을 만져줘야한다.
  • 프로젝트 내에서 vanilla extract를 이미 사용중이고, nextjs 기본 storybook 설정을 했다고 가정한다.

패키지 설치

  • dev dep에 해당 패키지들을 사용해야한다.
@storybook/addon-styling-webpack @vanilla-extract/webpack-plugin mini-css-extract-plugin
  • 이중 "@storybook/addon-styling-webpack" 애드온을 추가해주자.

storybook webpack 설정

  • config: StorybookConfig의 webpackFinal 프로퍼티에서 storybook webpack 설정을 할 수 있다.
  • webpackFinal은
    (config: Configuration, options: Options)를 받아
    Configuration | Promise<Configuration>) | undefined 를 리턴하는 콜백함수를 넣어준다.
  • vanilla extract 문서에서 제공해준 웹팩 설정에 맞게 webpackFinal을 작성해줄 것이다.
  // refer: <https://vanilla-extract.style/documentation/integrations/webpack/>
  // webpack.config.js
  const {
  VanillaExtractPlugin
} = require('@vanilla-extract/webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
  plugins: [
    new VanillaExtractPlugin(),
    new MiniCssExtractPlugin()
  ],
  module: {
    rules: [
      {
        test: /\\.vanilla\\.css$/i, // Targets only CSS files generated by vanilla-extract
        use: [
          MiniCssExtractPlugin.loader,
          {
            loader: require.resolve('css-loader'),
            options: {
              url: false // Required as image imports should be handled via JS/TS import statements
            }
          }
        ]
      }
    ]
  }
};
  • 따라서 webpackFinal의 결과물은 이렇게 나온다.
import { VanillaExtractPlugin } from "@vanilla-extract/webpack-plugin";
import MiniCssExtractPlugin from "mini-css-extract-plugin";

webpackFinal: (config) => {
        // ...other webpackFinal code

    config.plugins?.push(
      new VanillaExtractPlugin(),
      new MiniCssExtractPlugin()
    );

    config.module?.rules?.forEach((rule: any) => {
      if (
        typeof rule !== "string" &&
        rule?.test instanceof RegExp &&
        rule?.test?.test("test.css")
      ) {
        rule.exclude = /\\.vanilla\\.css$/i;
      }
    });

    config.module?.rules?.push({
      test: /\\.vanilla\\.css$/i, // Targets only CSS files generated by vanilla-extract
      use: [
        MiniCssExtractPlugin.loader,
        {
          loader: require.resolve("css-loader"),
          options: {
            url: false, 
          },
        },
      ],
    });

    return config;
  },
  • 의문이 드는 점은 중간에 rule.exclude를 하는 부분이다.
    • 해당 부분은 웹팩에서 일반적인 css 파일 처리에서 vanilla extract를 제외하기 위한 코드라고 한다.

테마 적용

  • preview: Preview에서 decortors 프로퍼티를 설정해줘야한다.
  • 전역적으로 스토리북 스토리를 감싸거나 provide할 데이터가 있을 때 설정한다.
    decorators: [
      (Story) => (
        <div className={`${createTheme로 만든 클래스네임}`}>
          <Story />
        </div>
      ),
    ],

어차피 해야할 것

  • webpackFinal에서 프로젝트내의 tsconfig설정을 적용해줘야한다.
    import * as path from "path";
    import { TsconfigPathsPlugin } from "tsconfig-paths-webpack-plugin";
    if (config.resolve) {
        config.resolve.plugins = config.resolve.plugins || [];
        // for alias @
        config.resolve.plugins.push(
          new TsconfigPathsPlugin({
            configFile: path.resolve(__dirname, "../tsconfig.json"),
          })
        );
      }
  • 이로서 path alias도 스토리북에 적용 가능하다.