nuxt.svg

【Nuxt 2】Storybookの導入

Nuxt2

Storybook とは

Storybook とは、Vue.js などのコンポーネント開発を補助するツールです。 作成したコンポーネントをある程度自動でドキュメント化できるため、コンポーネントの仕様をプロジェクトメンバーで共有できたりします。

Vue.js の Storybook についてはこちらにチュートリアルがありますので、よろしければ参考にしてください。 この記事では NuxtJS への導入について記述していきます。

Storybook の導入

インストール

NuxtJS への導入方法はいくつかありますが、@nuxtjs/storybookを使用します。

npm install --save-dev @nuxtjs/storybook postcss@latest

ストーリー

まずは動作を確認するために、以下のようにMyButtonコンポーネントと Storybook 用のファイル(**.stories.js)を作成します。 これは好みですが、Storybook 用にstoriesのようなフォルダを作成したりします。

components/
 ├ stories/
 │  └ MyButton.stories.js
 └ MyButton.vue
MyButton.vue
<template>
  <button
    :disabled="disabled"
    :style="style"
    @click="onClick"
  >
    <slot />
  </button>
</template>

<script>
export default {
  props: {
    color: {
      type: String,
      default: undefined
    },
    disabled: {
      type: Boolean,
      default: false
    }
  },
  computed: {
    style() {
      return {
        'background-color': this.color
      }
    }
  },
  methods: {
    onClick(event) {
      this.$emit('click', event)
    }
  }
}
</script>
MyButton.stories.js
import MyButton from '../MyButton'

export default {
  title: 'Button',
  component: MyButton,
}

//1つ目が基準。
export const Default = () => '<my-button>Button</my-button>'

//2つ目以降がstoriesとして追加される。
export const Color = () => `
  <div>
    <my-button color="red">Red</my-button>
    <my-button color="blue">Blue</my-button>
    <my-button color="green">Green</my-button>
  </div>
`

起動

Storybook は、以下のコマンドで起動します。 コンソールに表示された URL にアクセスして、起動していることを確認してください。

npx nuxt storybook

画面中の Docs を選択すると、画像のような画面が表示されるはずです。 詳細は後述します。

アドオン

Storybook は、アドオンとして機能を追加することができます。 アドオンの追加方法については後述します。

@nuxtjs/storybookには、デフォルトで@storybook/addon-essentialsというアドオンが導入されています。 このアドオンにより、以下のアドオンがまとめて導入されます。 それぞれのアドオンの説明は割愛します。

設定

Storybook に関する設定は、nuxt.config.jsstorybookに記述します。

nuxt.config.js
export default {
  //...
  storybook: {
    //アドオンを追加します。
    //@storybook/addon-essentialsは設定不要です。
    addons: [
      '@storybook/addon-controls',
      {
        name: '@storybook/preset-scss',
        options: {
          cssLoaderOptions: {
              modules: true,
              localIdentName: '[name]__[local]--[hash:base64:5]',
          }
        }
      }
    ],
    //ストーリーファイルの場所を指定します。
    stories: [
      '~/components/stories/*.stories.js'
    ],
    //起動するポートを設定します。
    port: 4000,
    //パラメーターは、アドオンなどを制御するための値です。
    //ここでは、すべてのストーリーに適用されるグローバルパラメーターを設定します。
    parameters: {
      backgrounds: {
        default: 'white',
        values: [
          { name: 'white', value: '#ffffff' },
          { name: 'gray', value: '#aaaaaa' }
        ]
      }
    },
    //ストーリーに適用するタグを設定します。
    decorators: [
      '<div id="__nuxt"><story /></div>'
    ]
  }
}

ストーリーの作成

上述したMyButton.stories.jsを基に、ストーリーの作成について記述します。

タイトル

ストーリーのタイトルは、コード中のexport default {}titleに設定します。 タイトルをComponent/ButtonComponent/TextFieldのようにスラッシュで区切ることで、グルーピングが可能です。

ストーリーの追加

ファイルにexport const <Story Name>を定義することでストーリーを追加できます。 上例では、Default と Color というストーリーを定義しています。

ストーリーが 1 つの場合、タイトルと同じ名前にすることで余計な階層を省略できます。

Docs では、1 つ目に定義したものが基準のストーリーとなり、コンポーネント情報の表が表示されます。 2 つ目以降に定義したものが Stories として表示されます。

argTypes

export default {}argTypesを設定することで、コンポーネントの情報を設定します。 ある程度は自動で設定されるようになっているため、必要なものだけ設定すれば OK です。

MyButton.stories.js
export default {
  title: 'Button',
  component: MyButton,
  argTypes: {
    color: {
      description: '`background-color`を設定します。',
      defaultValue: 'red',
      control: {
        type: 'select',
        options: ['red', 'blue', 'green']
      }
    },
    disabled: {
      description: 'ボタンを使用不可に設定します。'
    },
    click: {
      description: 'クリック時に発火するイベントです。'
    },
    default: {
      description: 'デフォルトのslotです。'
    }
  }
}

argTypesの設定を反映するために、1 つ目のストーリーを以下のように変更します。

MyButton.stories.js
export const Default = (args, { argTypes }) => ({
  props: Object.keys(argTypes),
  components: { MyButton },
  template: '<my-button v-bind="$props">Button</my-button>'
})

Control

Control は、コンポーネントのプロパティを動的に変更するための機能です。 ここでプロパティを変更することで、コンポーネントの動きや見た目の変化を確認することができます。

上記のargTypesの設定により、表に Control の列が追加されています。 ここに設定された入力欄により、プロパティを動的に変更することができます。

この入力欄の種類は、コンポーネントのプロパティタイプによって自動で設定されます。 種類を変更したい場合は、argTypescontrolを設定します。

Control の種類(type)には、以下のものがあります。

type
booleancontrol { type: 'boolean' }
numbercontrol { type: 'number', min: 0, max: 50, step: 5 }
rangecontrol { type: 'range', min: 0, max: 50, step :5 }
textcontrol { type: 'text' }
datecontrol { type: 'date' }
colorcontrol { type: 'color' }
objectcontrol { type: 'object' }
filecontrol { type: 'file' }
radiocontrol { type: 'radio' }, options ['one', 'two', 'three']
inline-radiocontrol { type: 'inline-radio' }, options ['one', 'two', 'three']
checkcontrol { type: 'check' }, options ['one', 'two', 'three']
inline-checkcontrol { type: 'inline-check' }, options ['one', 'two', 'three']
selectcontrol { type: 'select' }, options ['one', 'two', 'three']
multi-selectcontrol { type: 'multi-select' }, options ['one', 'two', 'three']

またdefaultValueにより、Control の初期値を設定することができます。

Actions

イベントの動作を確認するためにactionを設定します。

まずはargTypesの対象のイベントにactionを設定します。

MyButton.stories.js
export default {
  //...
  argTypes: {
    //...
    click: {
      description: 'クリック時に発火するイベントです。',
      action: 'click'
    }
  }
}

次に対象のtemplateにイベントを設定します。

MyButton.stories.js
export const Default = (args, { argTypes }) => ({
  //...
  template: '<my-button v-bind="$props" @click="click">Button</my-button>'
})

Canvas 画面に移動し、対象のイベントを発火させます。 イベントが発火すると、画面下の Actions に情報が表示されます。