본문으로 바로가기

Storybook 시작하기 (feat. vue)

category Helloworld!/Vue 2024. 1. 17. 16:28

Install

1. Storybook CLI 사용해 설치한다.

npx sb init
  • 루트 안에 .storybookstorybook-static 추가된다.
  • package.json 에 명령어 추가된다.
...
"storybook": "start-storybook -p 6006",
"build-storybook": "build-storybook"
...

 

2. .gitignore 에 다음과 같이 추가한다.

.storybook
storybook-static

 

3. Stroybook 을 다음 명령어로 실행한다.

npm run storybook
  • http://localhost:6006 로 Storybook 자동 실행 된다.

 

Setting

.storybook/main.js 에서 스토리 위치 외 Storybook 에 관련된 다양한 옵션들을 세팅할 수 있다.

 

 

1. 스토리 위치 세팅

  • .storybook/main.js 를 보면 Stroybook 설치 시 기본 세팅이 다음과 같이 stories 폴더 하위에 스토리가 위치하도록 되어있다.
module.exports = {
  "stories": [
    "../stories/**/*.stories.mdx",
    "../stories/**/*.stories.@(js|jsx|ts|tsx)",
  ],
  ... 

 

  • components 내부에 Component.vue 와 동일한 이름으로 같이 있는게 대세 같아 다음과 같이 수정했다.
module.exports = {
  "stories": [
    "../components/*.stories.@(js|jsx|ts|tsx)"
  ],
  ...

 

2. scss 세팅 # 

  • 다음 명령어 실행한다.
npm install @storybook/preset-scss css-loader sass sass-loader style-loader --save-dev
  • .storybook/main.js 의 addon 에 설치한 preset-scss 추가한다.
module.exports = {
  ...
  "addons": [
    ...
    '@storybook/preset-scss'
  ],
  ...
}

 

Example

Storybook 에선 Component 를 Library, 예시를 Story 라고 부른다.
  • Button Story 를 추가해봤다.

 

  • CommonButton.vue
<template>
  <button type="button" :class="classes" @click="onClick" :style="style">{{ label }}</button>
</template>

<script lang="ts">
import { Component, Prop, Vue } from 'nuxt-property-decorator'

@Component
export default class Button extends Vue {
  @Prop({ type: String, required: true })
  label: string

  @Prop({ type: Boolean, default: false })
  primary: boolean

  @Prop({ type: String, default: 'medium', validator: (value) => { return ['small', 'medium', 'large'].indexOf(value) !== -1; } })
  size: string

  @Prop({ type: String })
  backgroundColor!: String

  get classes() {
    return {
      'CommonButton': true,
      'CommonButton--primary': this.primary,
      'CommonButton--secondary': !this.primary,
      [`CommonButton--${this.size}`]: true,
    };
  }

  get style() {
    return {
      backgroundColor: this.backgroundColor,
    };
  }

  onClick() {
    this.$emit('onClick');
  }
}
</script>

<style lang="scss">
.CommonButton {
  font-weight: 700;
  border: 0;
  border-radius: 3em;
  cursor: pointer;
  display: inline-block;
  line-height: 1;

  &--primary {
    color: white;
    background-color: #1ea7fd;
  }

  &--secondary {
    color: #333;
    background-color: transparent;
    box-shadow: rgba(0, 0, 0, 0.15) 0 0 0 1px inset;
  }

  &--small {
    font-size: 12px;
    padding: 10px 16px;
  }

  &--medium {
    font-size: 14px;
    padding: 11px 20px;
  }

  &--large {
    font-size: 16px;
    padding: 12px 24px;
  }
}
</style>
  • CommonButton.stoires.ts
import CommonButton from './CommonButton.vue';

export default {
  title: 'Example/Button',
  component: CommonButton,
  decorators: [withDesign],
  argTypes: {
    backgroundColor: { control: 'color' },
    size: {
      control: { type: 'select' },
      options: ['small', 'medium', 'large'],
    },
  }
} as CompomentMeta<typeof CommonButton>;

const CommonButtonStory: ComponentStory<typeof CommonButtonStory> = (args, { argTypes }) => ({
  props: Object.keys(argTypes),
  components: { CommonButton: CommonButton },
  template: '<CommonButton @click="onClick" v-bind="$props" />'
});

export const Primary = CommonButtonStory.bind({});
Primary.args = {
  primary: true,
  label: 'Button',
};

export const Secondary = CommonButtonStory.bind({});
Secondary.args = {
  label: 'Button',
};

export const Large = CommonButtonStory.bind({});
Large.args = {
  size: 'large',
  label: 'Button',
};

export const Small = CommonButtonStory.bind({});
Small.args = {
  size: 'small',
  label: 'Button',
};

Responsive Test

1. Canvas > Change the size of the preview 버튼 클릭

 

2. 원하는 화면 선택

3. 직접 Viewport 추가하는 방법

// .stroybook/preview.js

export const parameters = {
  viewport: {
    iphone5: {
      name: 'iPhone 5',
      styles: {
        height: '667px',
        width: '375px',
      },
      type: 'mobile',
    },
    iphoneXr: {
      name: 'iPhone XR',
      styles: {
        height: '896px',
        width: '414px',
      },
      type: 'mobile',
    },
    ...
  }
}

 

4. 기본적으로 Storybook 에서 제공하는 Viewport 세팅 하는 방법 #

// .storybook/preview.js

import { INITIAL_VIEWPORTS } from '@storybook/addon-viewport';

export const parameters = {
  viewport: {
    viewports: INITIAL_VIEWPORTS,
  },
};

 

5. 특정 예시에 기본 Viewport 지정하는 방법

  • CommonButton 스토리에 Viewport 를 Storybook 에서 제공하는 Viewport 세팅하고, 기본적으로 보여질 화면을 아이폰 6로 지정한 예시이다. Component parameters 를 사용해 설정할 수 있다.
export default {
  title: 'Example/Button',
  component: CommonButton,
  parameters: {
    viewport: {
       viewports: INITIAL_VIEWPORTS,
       defaultViewport: 'iphone6'
    }
  },
 ...
} as CompomentMeta<typeof CommonButton>;

 

  • CommonButton 스토리 중 primary 버튼에 Viewport 를 지정 후 기본적으로 보여질 화면을 아이폰 X 로 지정한 예시이다. 스토리 parameters 에 Viewport 를 추가하면 된다.
Primary.parameters = {
  viewport: {
    viewports: INITIAL_VIEWPORTS,
    defaultViewport: 'iphonex'
  }
};

Addon Figma

1. storybook-addon-designs 설치한다. #

npm install --save-dev storybook-addon-designs

 

2. .storybook/main.js 의 addon 에 storybook-addon-designs 추가한다.

module.exports = {
  ...
  "addons": [
    ...
    'storybook-addon-designs'
  ],
  ...
}

 

 

3. CommonButton.storires.ts 에 다음 코드를 추가한다.

export default {
  ...
  decorators: [withDesign],
  parameters: {
    design: {
      type: 'figma',
      url:
        'https://www.figma.com/file/LKQ4FJ4bTnCSjedbRpk931/Sample-File'
    },
  },
  ...
};

 

4. Design 탭에서 연동된 Figma 를 확인할 수 있다.

 

5. Story 별로 Figma 연동하고 싶을 경우는 다음과 같이 작성하면 된다.

export default {
  ...
  decorators: [withDesign],
  ...
};
...
Primary.args = {
  primary: true,
  label: 'Button',
};
Primary.parameters = { //Primary Story 에만 figma 연동
  design: {
    type: 'figma',
      url:
    'https://www.figma.com/file/LKQ4FJ4bTnCSjedbRpk931/Sample-File',
  },
}