Storybookとは、一言で表すならばコンポーネント見本市。コンポーネント志向が絶賛推し進められているフロントエンド界隈にて注目度が上がり続けている(のではないかと予想)される期待の開発ツールなのである。

どんな機能を持っているのかというと、作ったコンポーネントを単体で整列表示することができる。まさに見本市。
大雑把に言ってしまえばそれだけである。しかしフロントエンド開発を一度でも経験したことがある壮年層ならもうすでにピンと来ているに違いない。
そう、画面全体を表示することなく、目的の箇所まで画面操作をすることなく、作ったコンポーネントを、好きなプロパティを代入して、単体で表示することができるのである。
公式サイトに利用イメージがあるのでそちらも参考に。

ただいくつか問題があり、一番大きなものはReactを想定して作られていること。Reactを使っているなら何も問題はないが、俺はVueを使いたいんだという青少年にとっては乗り越えるべき壁はまだまだ多い。
だが安心して欲しい、Storybookは(先々月くらいから)正式にVueに対応している。資料の少なさという壁さえ乗り越えられたらStorybookはVueで使える。

前書きが長くなりすぎので本題に入ると、今回はvue-cliで作ったプロジェクトにStorybookを導入するまでの手順を紹介。

vue-cliセットアップ

Storybookに興味を持つくらいならvue-cliでサクッとプロジェクトを作れるに違いないということで省略。あとyarnも。

Storybookインストール

導入ガイドを参考に手動でも良いが、getstorybookコマンドを使うと起動スクリプトや設定ファイルも作ってくれるので簡単。

まずはグローバルにツールをインストール。

npm i -g @storybook/cli  

vue-cliで作っておいたプロジェクトのルートディレクトリで下記コマンド実行。

getstorybook  

とりあえず実行して動作確認。初期状態だとポート6006でサーバが起動するのでブラウザで画面表示できたらここまでは成功。

yarn run storybook  

story-routerインストール

なんと最近(2日前)storybook-routerがvue-routerに対応した。有志に感謝を捧げてありがたく導入。

yarn add storybook-router  

Storybookのwebpack設定

Storybookには専用のwebpack設定があり、これはvue-cliで作ったプロジェクトのwebpack設定とは独立している。なのでいくつか設定を移植しないとこんな感じの思わぬエラーに遭遇しまくる事になる。

  • .vue拡張子を省略してimportできない
  • @のaliasが解決されない
  • スタイルシートをimportできない
  • logo.pngが表示されない

ということで、設定ファイルを設置する。基本的にはvue-cli側のwebpack設定を移植してきただけ。vue-loaderなども一緒に移植してしまうとエラーになってしまうので注意(詳細不明)。
webpack設定の拡張については公式にも説明があるので参照。


追記 style系loaderがinstallされてないよエラーがでてしまう場合のでinstallが必要
yarn add -D style-loader sass-loader


.storybook/webpack.config.js

const path = require('path')  
const utils = require('../build/utils')

function resolve(dir) {  
  return path.join(__dirname, '..', dir)
}

module.exports = {  
  resolve: {
    extensions: ['.js', '.vue', 'json'],
    alias: {
      vue$: 'vue/dist/vue.esm.js',
      '@': resolve('src')
    }
  },
  module: {
    rules: [
      {
        test: /\.(scss|css)$/,
        loaders: ['style-loader', 'css-loader', 'sass-loader']
      },
      {
        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: utils.assetsPath('img/[name].[hash:7].[ext]')
        }
      },
      {
        test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: utils.assetsPath('media/[name].[hash:7].[ext]')
        }
      },
      {
        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
        }
      }
    ]
  }
}

Storybook設定

基本的にはそのままでも問題ないが、storyファイルを1つずつ読み込むのは面倒なのでディレクトリ丸ごと読み込むように変更する。
以下の設定では、srcディレクトリ以下の.story.jsという拡張子を持つファイルをstoryファイルとして読み込む。
参考にしたのはこちら

ちなみにgetstorybookは初期状態だとsrc/storiesにstoryファイルを作ってねという設定になっている。以下の設定ではコンポーネントの.vueファイルに隣接してstoryファイルを作ることを想定しているのでsrc/storiesディレクトリは削除してしまう。このあたりは好みの問題だったりするのでお好きな設定で。

.storybook/config.js

import { configure } from '@storybook/vue'

const req = require.context('../src', true, /\.story\.js$/)

function loadStories() {  
  req.keys().forEach(filename => req(filename))
}

configure(loadStories, module)  

vuexなどを使う場合はこの設定でグローバルに有効にしておく。
グローバルに使うスタイルシート(ressとか)もここで有効にしておけばOK。

import 'ress'  
import Vue from 'vue'  
import Vuex from 'vuex'

Vue.use(Vuex)  

story作成

面倒な設定は済んだ、さぁ少年、君だけのstoryを作れ。
と投げ出したいところだがせっかくなのでvue-cliに用意されているApp.vueのstoryサンプルを掲載。ついでにstorybook-routerも使ってみる。

src/App.story.js

import { storiesOf } from '@storybook/vue'  
import StoryRouter from 'storybook-router'

import App from './App'  
import router from './router'

storiesOf('App', module)  
  .addDecorator(
    StoryRouter(
      {},
      {
        routes: router.options.routes,
        initialEntry: '/hoge'
      }
    )
  )
  .add('to Storybook', () => ({
    components: { App },
    template: `
      <div>
        <router-link to="/">Home</router-link>
        <router-link to="/hoge">Hoge</router-link>
        <hr/>
        <App />
      </div>
    `
  }))

StoryRouter関数の第2引数に各種設定を渡す。アプリで使っているrouterをimportしてrouter.options.routesをroutesとして渡せばそのままルーティング設定を使うことができる。initialEntryはデフォルトで採用されるパスを設定可能。
templateにrouter-linkを使ったリンクを入れておくと画面遷移操作ができるようになるのでおすすめ。
storybook-routerの使い方はここの下の方にも書かれてるので参照。
storyの使い方サンプルはこちらに多数作ってくれているので一通り眺めてみることを推奨。

Storybookにはコメント機能やdoc風な機能を追加できるなど様々なアドオンがあり、それらを組み合わせていくとさらなる真価を発揮する。
しかしvueにはまだ本体が対応したばかりでアドオンの説明欄には、「This addon works with Storybook for: React.」と書かれてしまっているものばかり。
とはいえ本体の機能だけでも十分に強力なことは最初に述べた通り。
Vue + Storybook 是非ともお試しあれ。