LoginSignup
24
15

More than 3 years have passed since last update.

【Nuxt.js / Storybook】インストールとaddonの導入まで(StoriesOf APIではなく最新ver推奨のCSF記法で)

Last updated at Posted at 2019-11-26

追記
新しいバージョンでは、.storybook/webpack.config.jsに設定を記述するのではなく.storybook/main.js.storybook/preview.jsを利用するようです。詳細は公式ドキュメントをご確認ください。


新規でNuxt(Vue)のプロジェクトを立ち上げる機会があったので、初めてStorybookを導入してみました。
現在Storybookのバージョンは5.2.xですが、公式が推奨するストーリーの記述方式がComponent Story Format (CSF)に変更されたようです。
(v5.1以前はStoriesOf APIが一般的。v5.2でも問題なく使用できる)
Component Story Format (CSF)
StoriesOf API
初導入にあたり参考情報を探していたのですが、公式ドキュメントもネットの情報もStoriesOf APIでの記載例が多かったので(当たり前ですが)、良い機会だと思い基本的な情報ですがCSFでの記法でまとめでみました。

1.インストールと基本設定

Storybook for Vue
CLIを使用して半自動でインストールする方法と、必要なモジュールを自分で追加していく方法がありますが、CLIでインストールする方がやはり楽です。

1.1 NuxtプロジェクトにStorybookをCLIでインストール

CLIを使用すると雛形のStoryファイルが生成されるのでそれを見るだけでも基本的な使用方法はわかると思います。

$ npx -p @storybook/cli sb init

上記の書き方で、プロジェクトが何のフレームワークで構成されているか自動で判定して必要なモジュール群をインストールしてくれます(心配な場合はオプションでフレームワーク名を追加してください。--type vue)
作ったばかりのNuxtプロジェクトですが、以下のモジュールが追加されました。

+ @babel/core@7.7.2
+ babel-loader@8.0.6
+ babel-preset-vue@2.0.2
+ @storybook/addons@5.2.6
+ @storybook/addon-actions@5.2.6
+ @storybook/addon-links@5.2.6
+ @storybook/vue@5.2.6

さらに、storybookの設定ファイルなどを格納する.storybookとストーリーファイルを格納するstoriesの2つのディレクトリも同時に生成されます。

1.2 package.jsonの設定

実行する際のコマンドを追加します。が、CLIでインストールするとこの記述も追加されていますので、特に編集はいりません。Dockerなどを使用している関係でポート番号を変更したいなどありましたら編集してください。

"scripts": {
  "storybook": "start-storybook -p 6006",
  "build-storybook": "build-storybook"
}

これで、下記コマンドによる実行ができるようになりました。

$ npm run story

1.3 Storybook用webpackの設定

StorybookはNuxtなどと実行環境が別(この言い方で良いのか..?)なので、専用にwebpackの設定も行う必要があります。以下のファイルを編集していきます。CLIによって自動生成されるはずですが、なかったら追加してください。
.storybook/webpackconfig.js

1.3.1 Nuxtプロジェクトで使用している@~などのエイリアス設定

Nuxtプロジェクトからコンポーネントの読み込みをした際に、@~などのエイリアスを使用している場合エラーになるので追記しましょう。
Nuxtのプロジェクトディレクトリを移動している場合は適宜rootPathの値を変更してください。

 .storybook/webpack.config.js
const path = require('path')
const rootPath = path.resolve(__dirname, '../')
// Nuxtのプロジェクトをsrc以下に移動しいる場合
// const rootPath = path.resolve(__dirname, '../src/')

module.exports = ({ config }) => {

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

  return config
}

1.3.2 Typescriptの使用設定

Typescriptを使用する場合に。素のjsでプロジェクトを記述している場合は無視してください。

 .storybook/webpack.config.js
config.module.rules.push({
  test: /\.ts/,
  use: [
    {
      loader: 'ts-loader',
      options: {
        appendTsSuffixTo: [/\.vue$/],
        transpileOnly: true
      },
    }
  ],
});

1.3.3 scssの使用設定、かつ変数やmixinを使用している場合

Storybookで表示するコンポーネント内で、scssの変数やmixinを使用している場合はここで指定します。
以下のモジュールが追加されていない場合にはインストールしてください。

$ npm install --save-dev style-loader css-loader sass-loader @nuxtjs/style-resources
 .storybook/webpack.config.js
config.module.rules.push({
  test: /\.scss$/,
    use: [
      'style-loader', 'css-loader', 'sass-loader',
      {
        loader: 'sass-resources-loader',
        options: {
          resources: [ 
            './assets/scss/_variable.scss',
          ],
          rootPath  // path.resolve(__dirname, '../')
        }
      },
    ],
});

1.3.4 css内からassets以下のファイルにアクセスできるように設定

assetsディレクトリ以下の画像やフォントにcssからアクセスできるように設定します。

 .storybook/webpack.config.js
config.resolve.modules = [
  ...(config.resolve.modules || []),
  rootPath
];

基本的には、以上で設定は終わりです。

1.4 簡単なストーリーの記述

MyButtonコンポーネントを表示する、ごく基本的なストーリーの記述方を書きます。
Component Story Format (CSF)での書き方は、実際に記述してみれば結構簡単かと思います。
ストーリーは.storybook/config.jsの中にある以下の記述によって、/stories以下の.stories.jsがついたファイルが自動で読み込まれます。

 .storybook/config.js
// automatically import all files ending in *.stories.js
configure(require.context('../stories/', true, /\.stories\.js$/), module)
sample.stories.js
import MyButton from '@/components/MyButton'

// コンポーネントのメタデータを記述
// アドオンのでコレータやパラメータなどもここに書く
export default {
  // スラッシュで区切ると、Atoms>Buttonと階層構造で表示できます
  // 他にも記述方法はあるが割愛。公式ドキュメントを確認してください
  // タイトルは一意であること
  title: 'Atoms/Button',
  decorators: [ ... ],
  parameters: { ... }
}

// Common Link Btnがストーリーの名前となります。
export const CommonLinkBtn = () => ({
  components: MyButton,
  // 適宜htmlなりを記述
  template: `
  <div id="storybook-container">
    <div class='component-wrapper'>
      <h5>MyButton</h5>
      <Button>{{ label }}</ButtonLink>
    </div>
  </div>
  `
})

// 下記のように名称を変更できます
// CommonLinkBtn.story = { name: 'hoge' }


2. 代表的なaddonの追加

追加していくaddonは以下です。全てStorybookの公式です

アドオン 機能 github
addon-knobs 動的にpropsの値を変更して、コンポーネントの挙動を確認できる @storybook/knobs
actions onClickなどのUIアクションに対してのログを確認できる @storybook/addon-actions
notes text,html,マークダウンでコンポーネントの説明を追加できる @storybook/notes
viewport 表示サイズの変更 @storybook/viewport
a11y コンポーネントのアクセシビリティチェック @storybook/addon-a11y
backgrounds ストーリーの背景色変更 @storybook/addon-backgrounds

上記のアドオンをインストール&Storyに追加

$ npm i -D @storybook/knobs @storybook/addon-actions @storybook/notes @storybook/viewport @storybook/addon-a11y @storybook/addon-backgrounds

インストールしたアドオンをimportします。

 .storybook/config.js
// actionsとlinksはCLIによるインストール時に追加される。
// linksについては省略
import '@storybook/addon-links/register'
import '@storybook/addon-knobs/register'
import '@storybook/addon-actions/register'
import '@storybook/addon-notes/register'
import '@storybook/addon-viewport/register'
import '@storybook/addon-a11y/register'
import '@storybook/addon-backgrounds/register'

2.1 knobs

propsを設定したコンポーネントを用意します。

MyButton.vue
<template>
  <button :disabled="isDisabled">
    <slot></slot>
  </button>
</template>

<script>
export default {
  props: {
    isDisabled: {
      type: Boolean,
      default: false
    }
  }
}
</script>

ちなみにpropsだけでなく、slotの値の挿入などもOKです。

MyButton.story.js
import { withKnobs, text, boolean } from '@storybook/addon-knobs';
import MyButton from '@/components/MyButton.vue';

export default {
  title: 'Storybook Knobs',
  decorators: [ withKnobs ]
}

export const Button = () => ({
  components: { MyButton },
  props: {
    isDisabled: {
      // default: 与えるデータの型('ラベル', 初期値)
      default: boolean('Disabled', false)
    },
    text: {
      default: text('Text', 'Hello Storybook')
    }
  },
  template: `<MyButton :isDisabled="isDisabled">{{ text }}</MyButton>`
})

2.2 actions

下記のようなカスタムイベントを設定したコンポーネントを準備します。

MyButton.vue
<template>
  <button @click="sampleEvent">ボタン</button>
</template>

<script>
export default {
  methods: {
    sampleEvent (e) {
      this.$emit('clicked', e)
    }
  }
}
</script>

上記をactionsを使用して表示するストーリーは以下。

MyButton.stories.js
import { action } from '@storybook/addon-actions'
import MyButton from '@/components/MyButton.vue';

export default {
  title: 'Storybook Actions',
}

export const PostBtn = () => ({
  components: { Button },
  // カスタムイベントが発火すると、以下のactionが実行されます。
  methods: {
    log: action('Post!')
  },
  template: `<ButtonPost @clicked="log" />`
})

actionが実行された様子
スクリーンショット 2019-11-26 19.55.42.png

2.3 notes

parametersにテキストなり、マークダウンファイルを指定すればOKです。

sample.stories.js
import markdownNotes from './someMarkdownText.md';

export default {
  title: 'Storybook Notes',
  // テキストの場合
  parameters: { notes: 'Some Notes' },
  // マークダウンファイルの場合
  parameters: { notes: { markdown: markdownNotes } }
}

__(省略)__

2.4 viewport

Storybook全体に適用する場合は、.storybook/config.jsに設定を追記します。
公式ドキュメントの例に沿って、Kindle端末の画面サイズを追加します。

 .storybook/config.js
import { addParameters } from '@storybook/vue';
// viewportが初期設定しているデバイスのパラメータリストを読み込む
import { INITIAL_VIEWPORTS } from '@storybook/addon-viewport';

// Kindleのパラメータを設定
const newViewports = {
  kindleFire2: {
    name: 'Kindle Fire 2',
    styles: {
      width: '600px',
      height: '963px'
    }
  },
  kindleFireHD: {
    name: 'Kindle Fire HD',
    styles: {
      width: '533px',
      height: '801px'
    }
  }
}

// 初期パラメータと上記で設定したパラメータオブジェクトを追加
// ...INITIAL_VIEWPORTS,を再度追加しているのは表示順を
// INITIAL_VIEWPORTS > newViewportsにするため
addParameters({
  viewport: {
    viewports: {
      ...INITIAL_VIEWPORTS,
      ...newViewports,
    }
  }
})

// 上記の設定はconfigure(require.context~より前に記載すること
configure(require.context('../stories/', true, /\.stories\.js$/), module)

2.5 a11y

チェックしたいコンポーネントに読み込み、decolatorsに追加すればOK

sample.stories.js
import { withA11y } from '@storybook/addon-a11y'

export default {
  title: 'Sample',
  decorators: [ withA11y ]
}

__(省略)__

2.6 backgrounds

全体に適用する場合はconfig.jsに記述追加

 .storybook/config.js
import { addParameters } from '@storybook/vue'

addParameters({
  backgrounds: [
    { name: 'Sample BG 1', value: '#CCCCCC', default: true },
    { name: 'Sample BG 2', value: '#000000' },
  ],
});

// 上記の設定はconfigure(require.context~より前に記載すること
configure(require.context('../stories/', true, /\.stories\.js$/), module)

以上、私もまだ深いところまで触っていない&導入したばかりで間違い等あるかもしれませんが、基本的なところは抑えられているかと思います:pushpin:

24
15
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
24
15