Vue.js

Vue Storybook 적용 방법

Hoon1994 2022. 1. 11. 21:33

 

실무에서 스토리북을 도입하기 전에는 노션 문서에 UI 컴포넌트들의 사용 방법이나 스크린 샷등으로 어떤 컴포넌트인지 알 수 있도록 문서를 작성했다.

 

글로벌로 재사용하는 UI 컴포넌트의 개수가 엄청나게 많은 건 아니지만, 다른 사람이 만든 UI 컴포넌트를 사용할 때 문서를 보고 한눈에 파악하기가 쉽지 않다. 

 

스토리북을 예전에 사용해보긴 했지만, 워낙 바쁜 상황이어서 도입은 미뤘었는데, 시간될 때마다 스토리북을 설정해서 마침내 스토리북을 도입했다.

 

다만 스토리북을 도입할 때까지 쉽지는 않았는데, 기존에 사용하고 있던 Composition API, Vuetify, 기타 라이브러리 등에서 충돌이 발생했기 때문이다.

 

스토리북은 별개의 빌드를 구성하기 때문에 그에 따라 설정을 해줘야 한다. 

 

아래 명령어를 통해 우선 Storybook을 설치해야한다.

npx sb init

 

설치가 완료됐다면, 루트 경로에 .storybook이라는 폴더가 생성되고, main.js, preview.js가 생성된다.

여기에 현재 프로젝트와 관련된 설정을 해주어야 한다.

 

우선 main.js를 어떻게 설정했는지 코드를 보자.

 

const path = require('path');
const rootPath = path.resolve(__dirname, '../src');

module.exports = {
  "stories": [
    "../src/**/*.stories.mdx",
    "../src/**/*.stories.@(js|jsx|ts|tsx)"
  ],
  "addons": [
    "@storybook/addon-links",
    "@storybook/addon-essentials",
    "storybook-addon-designs",
    "@storybook/preset-scss"
  ],
  webpackFinal: async (config, { configType }) => {
    config.module.rules.push({
        test: /\.scss$/,
        use: ['style-loader', 'css-loader', {
            loader: 'sass-loader',
            options: {
                additionalData: `
                  @import "src/scss/variables.scss";
                  @import "src/scss/mixin.scss";
                  @import "src/scss/common.scss";
                `
            }
        }],
        include: path.resolve(__dirname, '../'),
    });

    config.resolve.modules = [
      ...(config.resolve.modules || []),
      path.resolve(__dirname, "../src"),
    ];    

    config.resolve.alias['@'] = rootPath;
    config.resolve.alias['~'] = rootPath;

    return config;
},
  "framework": "@storybook/vue"
}

 

stories와 addons는 굳이 설명하지 않아도 될 것 같고, 포인트만 짚어보자.

storybook-addon-designs는 storybook에서 피그마를 연동시키기 위해 추가했고,

preset-scss 같은 경우 scss를 사용한다면 추가하면 된다.

 

중요! webpackFinal 같은 경우 위 코드에선 scss를 사용할 수 있도록 설정한거고, additionalData는 scss 파일을 미리 import 시켜서 전역에 적용하는거라고 생각하면된다. 

 

아래 alias를 설정하는 것도 꽤나 중요한데, 보통 실무에서 상대경로가 아니라 절대경로로 파일을 가져오기 때문에 
스토리북 빌드할 때도 컴포넌트 안에서 다른 파일들을 절대 경로로 가져올 경우 위 설정을 해줘야 오류가 발생하지 않고 정상적으로 호출이 된다.

 

 

다음은 preview.js를 살펴보자

import 'es6-promise/auto';
import '@babel/polyfill';
import Vue from 'vue';
import Vuetify from 'vuetify'
import i18n from '../src/i18n';
import { extend } from 'vee-validate';
import compositionAPI from '@vue/composition-api';
import ko_KR_validate from '../src/locales/ko_KR_validate';
import registerValidate from '../src/plugins/validate';
import AwsImage from '../src/components/common-ui/AwsImage';
import { InlineSvgPlugin } from 'vue-inline-svg';
import VueI18n from 'vue-i18n';
import COLORS from '../src/constants/color-types';
import Vuex from 'vuex';
import modules from '../src/store/modules';
import 'vuetify/dist/vuetify.min.css'
import '!style-loader!css-loader!sass-loader!../src/scss/reset.scss';

Object.keys(registerValidate).forEach(rule => {
  extend(rule, {
    ...registerValidate[rule],
    message: ko_KR_validate[rule],
  });
});

Vue.use(compositionAPI);
Vue.use(InlineSvgPlugin);
Vue.use(Vuetify);
Vue.use(VueI18n);
Vue.use(Vuex);

const store = new Vuex.Store({
  modules,
})

Vue.component('AwsImage', AwsImage);

const vuetifyConfig = new Vuetify({
  breakpoint: {
    thresholds: {
      xs: 340,
      sm: 540,
      md: 768,
      lg: 1080,
    },
    scrollBarWidth: 24,
  },
  theme: {
    themes: {
      light: {
        primary: COLORS.LIGHT_PRIMARY,
        secondary: COLORS.LIGHT_SECONDARY,
        hint: COLORS.LIGHT_HINT,
        disabled: COLORS.LIGHT_DISABLED,
        error: COLORS.LIGHT_ERROR,
        warning: COLORS.LIGHT_WARNING,
        action: COLORS.LIGHT_ACTION,
        brand: COLORS.LIGHT_BRAND,
        caption: COLORS.LIGHT_CAPTION,
        tertiary: COLORS.LIGHT_TERTIARY,
      },
      dark: {
        primary: COLORS.DARK_PRIMARY,
      },
    },
  },
});

export const parameters = {
  actions: { argTypesRegex: "^on[A-Z].*" },
  controls: {
    matchers: {
      color: /(background|color)$/i,
      date: /Date$/,
    },
  },
  design: {
    type: 'figma',
    url: 'figma url',
  },  
}

export const decorators = [(_) => ({
    store,
    vuetify: vuetifyConfig,
    i18n,
    template: `
      <v-app>
        <v-main>
          <v-container fluid>
            <story />
          </v-container>
        </v-main>
      </v-app>`
})]

 

Vue.js의 main.js와 같은 역할을 한다고 보면되고, main.js에서 설정한 값들을 여기에도 적용해주면 된다.

 

store, vuetify, i18n 등을 사용하기 위해서 맨 아래 decorators에 등록해줘야 한다.

composition API, 라이브러리 등을 사용하려면 Vue.use로 추가해주면 스토리북 내에서 사용이 가능하다.

 

reset.scss 같은 경우 삽질을 좀 많이 했는데, main.js에서 additionalData에 추가하니 스타일 적용이 되지 않는 이슈가 있었고, 이를 preview.js에 적용하니 정상적으로 적용되었다.