익명의 개발노트

[vue.js] vue+storybook 적용하기 본문

코딩일기/TIL

[vue.js] vue+storybook 적용하기

캡틴.JS 2020. 3. 17. 13:13
반응형

storybook

1. 스토리 북이란?

Storybook 은 UI 컴포넌트를 직접 보면서 개발을 할 수 있는 환경을 제공하는 툴이다.

실제 프로젝트 내에서 실행 되는 것이 아니라 독립된 환경으로 실행한다.

순전히 UI 개발에 집중할 수 있게 해주며,기획,디자인,개발자와의 협업 구조에서 원활하게 커뮤케이션이 가능하며 개발 생산성을 향상

시킬 수 있다.

UI 개발을 하다 보면 빈번하게 일어나는 디자인 스펙 오류, 기획 프로세스 오류 등을 빠르게 확인 하여 수정 할 수 있으며,

개발자는 컴포넌트를 더욱 유연하고, 재사용 가능한 컴포넌트 개발을 할 수 있도록 도와준다.

Storybook 의 경우 현재 많은 회사에서 사용 하고 있으며, Airbnb, Slack, Coursera 등과 많은 리액트 오픈소스 프로젝트에서 사용 되고

있다.

 

2. vue에서 적용하기

2020.3.16일 날짜 기준으로 공식문서에 수동 설치를 해도 실행되지 않는다... 자동설치는 되었음..

그리고 다른 한글로 적혀진 블로그들의 예시를 봐도 실행이 되지 않는다...

따라서, 본 메뉴얼은 자동 설치 기준으로 적고자 한다.

1) 설치

아래 명령어를 실행하기 전에 vue-cli로 프로젝트를 생성 후에 그 프로젝트 폴더 안에서 아래 명령어로 설치해주면된다.

 npx -p @storybook/cli sb init --type vue

설치가 완료되면 아래와 같은 폴더들이 생성된다.

.storybook 폴더를 보면, main.js 파일이 생성됨을 알 수가 있다.

아래와 같이 main.js에 코드가 생성된 것을 볼 수 있다.

module.exports = {
  stories: ['../stories/**/*.stories.js'],
  addons: ['@storybook/addon-actions', '@storybook/addon-links'],
};

stories안에는 *.stories.js 또는 *.stories.ts 로 경로를 설정해준다.

addons은 스토리북의 추가 기능으로 설치를 하게 되면 , 아래 그림 하단부 actions 같이 시각적으로 보기 쉽게 표시가 됨을 볼 수 있다.

스토리보드

그리고 package.json을 보면 script 부분에 아래 그림과 같이 추가된 내용을 확인 할 수 있다.

pakage.json의 script

실행은 아래와 같다.

npm run storybook
//또는
yarn storybook

그리고 stories 폴더를 보면 4개의 파일이 있음을 볼 수 있다.

Welcome.js, MyButton.js, 0-Welcome.stories.js, 1-Button.stories.js

이 파일이 의미하는 내용은  파일명.stories.js 은 실질적으로 스토리 보드에 표시되는 부분이다. 

파일자체는 스토리보드 좌측에 파일 이름을 표시한다.

Welcome.stories.js 소스코드를 보면 아래와 같다.

import { linkTo } from '@storybook/addon-links';

import Welcome from './Welcome';

export default {
  title: 'Welcome',   //스토리보드 제목
  component: Welcome, //스토리보드에 표시될 컴포넌트 
};

export const ToStorybook = () => ({  //스토리보드 좌측 이름 클릭시 보여지는 부분들
  components: { Welcome },
  template: '<welcome :showApp="action" />',
  methods: { action: linkTo('Button') }, //표현방법 링크
});

ToStorybook.story = {
  name: 'to Storybook',
};

같은 폴더 안에 Welcome.js 파일을 보자

// eslint-disable-next-line no-console
const log = () => console.log('Welcome to storybook!');

export default {
  name: 'welcome',

  props: {
    showApp: {
      type: Function,
      default: log,
    },
  },

  data() {
    return {
      main: {
        padding: 15,
        lineHeight: 1.4,
        fontFamily: '"Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif',
        backgroundColor: '#ffffff',
      },

      logo: {
        width: 200,
      },

      link: {
        color: '#1474f3',
        textDecoration: 'none',
        borderBottom: '1px solid #1474f3',
        paddingBottom: 2,
      },

      code: {
        fontSize: 15,
        fontWeight: 600,
        padding: '2px 5px',
        border: '1px solid #eae9e9',
        borderRadius: 4,
        backgroundColor: '#f3f2f2',
        color: '#3a3a3a',
      },

      note: {
        opacity: 0.5,
      },
    };
  },

  template: `
    <div :style="main">
      <h1>Welcome to STORYBOOK</h1>
      <p>
        This is a UI component dev environment for your app.
      </p>
      <p>
        We've added some basic stories inside the
        <br />
        <code :style="code">src/stories</code>
        <br />
        directory.
        <br />
        A story is a single state of one or more UI components. You can have as many stories as
        you want.
        <br />
        (Basically a story is like a visual test case.)
      </p>
      <p>
        See these sample
        <br />
        <a :style="link" @click="onClick" role="button" tabIndex="0">stories</a>
        <br />
        for a component called
        <br />
        <code :style="code">Button</code>
        .
      </p>
      <p>
        Just like that, you can add your own components as stories.
        <br />
        You can also edit those components and see changes right away.
        <br />
        (Try editing the <code :style="code">Button</code> component
        located at <code :style="code">src/stories/Button.js</code>.)
      </p>
      <p>
        This is just one thing you can do with Storybook.
        <br />
        Have a look at the
        <br />
        <a
          :style="link"
          href="https://github.com/storybookjs/storybook"
          target="_blank"
          rel="noopener noreferrer"
        >
          Storybook
        </a>
        <br />
        repo for more information.
      </p>
      <p :style="note">
        <b>NOTE:</b>
        <br />
        Have a look at the
        <br />
        <code :style="code">.storybook/webpack.config.js</code>
        <br />
        to add webpack
        loaders and plugins you are using in this project.
      </p>
    </div>
  `,

  methods: {
    onClick(event) {
      event.preventDefault();
      this.showApp();
    },
  },
};

js파일에 css, template 가 들어가있다. 실제로 현업에서 사용하려면, 이런식으로는 작업을 못하기에 실제 컴포넌트 불러오는 방법을 

알아보도록 하자.

src폴더 밑에 components 폴더 안에 Button.vue를 하나 만든다.

<template>
    <button class="button" :class="`button-color--${color}`">
        <slot></slot>
    </button>
</template>

<script>
export default {
  name: 'Button',
  props: {
    color: {
      type: String,
      default: 'normal'// 'normal' or 'primary'
    }
  }
};
</script>

<style scoped>
.button {
    appearance: none;
    border: none;
    font-family: sans-serif;
    padding: 8px 16px;
    border-radius: 2px;
}

.button-color--normal {
    background-color: #eee;
    color: #222;
}

.button-color--normal:hover,
.button-color--normal:focus {
    background-color: #e0e0e0;
}

.button-color--normal:active {
    background-color: #bdbdbd;
}

.button-color--primary {
    background-color: #2196f3;
    color: #fff;
}

.button-color--primary:hover,
.button-color--primary:focus {
    background-color: #1e88e5;
}

.button-color--primary:active {
    background-color: #1976D2;
}
</style>

버튼 컴포넌트를 생성하였으면, 스토리 폴더에서 버튼 스토리를 하나 만든다.

Button.stories.js

import Button from '../src/components/shared/Button.vue';

export default {
  title: 'Button' //스토리북 좌측 타이틀
};

//스토리북 위 버튼이란 타이틀안에 소타이틀
export const normalButton = () => ({ 
  components: { Button },
  template: '<Button>Normal Button</Button>'
});

export const primaryButton = () => ({
  components: { Button },
  template: '<Button color="primary">Normal Button</Button>'
});

위와 같이 작성하고 저장 후 yarn storybook 또는 npm run storybook 을 실행하면, 스토리북 창이 뜬다.

이렇게 내가 만든 컴포넌트를 스토리폴더에서 컴포넌트를 똑같이 생성 후에 테스트 해볼 수가 있다.

위와 같은 방법이 불편하다면 아래와 같은 방법으로 해볼 수도 있다.

버튼 컴포넌트는 건들지 말고, stories 폴더에 ButtonNormal.story.vue, ButtonPrimary.story.vue 파일을 아래와 같이 만들어 주고

//ButtonNormal.story.vue

<template>
    <Button>Normal Button</Button>
</template>

<script>
import Button from '../src/components/shared/Button.vue';

export default {
  name: 'ButtonNormal',
  components: { Button },
};
</script>
//ButtonPrimary.story.vue

<template>
    <Button color="primary">Primary Button</Button>
</template>

<script>
import Button from '../src/components/shared/Button.vue';

export default {
  name: 'ButtonPrimary',
  components: { Button },
};
</script>

Button.stories.js 파일을 아래와 같이 수정한다.

import ButtonNormal from './ButtonNormal.story.vue';
import ButtonPrimary from './ButtonPrimary.story.vue';

export default {
  title: 'Button'
};

export const normalButton = () => ButtonNormal;

export const primaryButton = () => ButtonPrimary;

스토리북을 실행시키면, 아까 그림과 같이 똑같이 스토리북에 컴포넌트가 뜬다.

이건 가장 기본적인 튜토리얼이며, 여기서 추가적으로 애드온을 설치해서 더 잘 활용하면 된다.

스토리북의 장점으로는 문서화가 가능하다는 것인데, 애드온 docs을 이용해서 Netflify에 정적으로 배포해서 

문서용으로 사용하면 좋다. 

생각보다 애드온은 리액트에서 사용하는 것보다 적게 풀려있다. 아직 뷰 자체가 스토리북에 적응하지 못한 것일 수도..

 

반응형
Comments