追記
新しいバージョンでは、.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
の値を変更してください。
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でプロジェクトを記述している場合は無視してください。
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
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からアクセスできるように設定します。
config.resolve.modules = [
...(config.resolve.modules || []),
rootPath
];
基本的には、以上で設定は終わりです。
1.4 簡単なストーリーの記述
MyButton
コンポーネントを表示する、ごく基本的なストーリーの記述方を書きます。
**Component Story Format (CSF)**での書き方は、実際に記述してみれば結構簡単かと思います。
ストーリーは.storybook/config.js
の中にある以下の記述によって、/stories
以下の.stories.js
がついたファイルが自動で読み込まれます。
// automatically import all files ending in *.stories.js
configure(require.context('../stories/', true, /\.stories\.js$/), module)
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します。
// 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を設定したコンポーネントを用意します。
<template>
<button :disabled="isDisabled">
<slot></slot>
</button>
</template>
<script>
export default {
props: {
isDisabled: {
type: Boolean,
default: false
}
}
}
</script>
ちなみにpropsだけでなく、slotの値の挿入などもOKです。
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
下記のようなカスタムイベントを設定したコンポーネントを準備します。
<template>
<button @click="sampleEvent">ボタン</button>
</template>
<script>
export default {
methods: {
sampleEvent (e) {
this.$emit('clicked', e)
}
}
}
</script>
上記をactions
を使用して表示するストーリーは以下。
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" />`
})
2.3 notes
parameters
にテキストなり、マークダウンファイルを指定すればOKです。
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端末の画面サイズを追加します。
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
import { withA11y } from '@storybook/addon-a11y'
export default {
title: 'Sample',
decorators: [ withA11y ]
}
__(省略)__
2.6 backgrounds
全体に適用する場合は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)
以上、私もまだ深いところまで触っていない&導入したばかりで間違い等あるかもしれませんが、基本的なところは抑えられているかと思います