StorybookはReactなどのUIコンポーネントをリスト表示して動作確認するツールです。addonを利用して入力値ごとの挙動を確認することも可能です。
インストール
npmでstorybookを追加したうえで、storybook init
コマンドを実行することで関連パッケージが一式入ります。
$ npm install --save-dev storybook
$ npx storybook init
Storybookに後から機能追加していく際、各種configを編集することになります。
Storybookは、TypescriptやJSXのトランスパイルにBabelを、バンドルにはWebpackを利用しています。メインのプロジェクトでtscやrollupなどのビルドツールを採用している場合にもstorybook init
がwebpack/babelなどを追加セットアップします。
また、storybook用のconfigはプロジェクトのconfigではなく.storybook/
を参照します。そのため、プロジェクトのツールチェインに関わらずStorybookをセットアップできます。ただ、パッケージは肥大化することと、Storybookのconfigはwebpack/babelを設定する必要がある点はトレードオフです。
.storybook/main.js
Storybookの基礎的なconfigは.storybook/main.js
です。基本的にはstories
属性のpathが適切であれば動作します。初期状態ではstorybook init
が生成するサンプルのストーリー(ギャラリー表示するコンポーネント)を指しており、このディレクトリを採用しても問題ありません。pathさえ適切であれば別のディレクトリも設定可能です。
また、webpackのレイヤで追加設定したい場合、main.jsの
webpackFinal属性にwebpack.config.jsのパーツを書くという構成になっており、拡張の際には注意が必要です。
これは、Storybookが内包しているwebpackのconfigをオーバーレイするための構成ですが、猛烈に分かりにくいポイントです。
なお、config.jsやaddons.jsなどはv7で削除予定の古いconfigフォーマットで、 移行の警告が表示されるため情報源に注意します。
Preact向けBabel拡張
StorybookはReact向けにセットアップするため、JSXや基本的なTypescriptについては初期状態で対応済になっています。
JSXライブラリとしてPreactを利用している場合、h()
の解決が追加で必要になります。これはBabelのレイヤで対応するため、.storybook/main.js
に以下のような
Babel設定を追加することで吸収できました。
module.exports = {
babel: async (options) => ({
...options,
presets: [
'@babel/preset-env',
['@babel/preset-typescript', { jsxPragma: 'h' }, 'preact-preset']
],
plugins: [
['@babel/transform-react-jsx', { pragma: 'h' }, 'preact-plugin']
]
})
}
なお、configで追加指定するBabelのプラグインはnpm install --savedev @babel/plugin-transform-react-jsx
のように手動でインストールしておきます。
要するに、Babelの機能追加はBabelのレイヤで対応するという当たり前のことですが、StorybookのドキュメントはWebpack/Babelに言及せずに書かれているため、気づきにくいポイントと言えます。
またこの例はPreactですが、Typescriptのクラスプロパティを使いたい場合なども同様にBabelのプラグイン追加&config定義します。
Storyの記述と実行
ギャラリーの表示内容は、生成されたサンプルを参考に、各プロジェクトのコンポーネントを表示するストーリーを記述します。表示対象のコンポーネントは、各ストーリー冒頭のimport
文でpathベースで参照するだけで、追加の設定は不要です。
ストーリーについては実行環境による差がほとんどないため、
公式ドキュメントが参考になります。
ドキュメント
スタティックなドキュメントについては、MDX形式で記述する方法があります。
各ストーリーへのコメント程度で足りる場合には、以下のようにCSFのexport default
のパラメータとして指定する方法もあります。
export default {
title: 'Some story',
parameters: {
docs: {
description: {
component: "ストーリーのトップブロックに表示されます。markdownで装飾可能"
}
}
}
};
また、コンポーネントのpropsを表形式で表示する機能もあります。Reactの場合は、以下のようにexport default
にコンポーネントを指定すると表示できるようです。
export default {
title: 'Some story',
component: SomeComopnent
};
Preactでは自動でリスト抽出できませんが、
argsの形式でStoryを書くとArgsTableを表示できます。
なお、Storybookの意図としてはコンポーネントのソースからJSDocのPropTypesを参照して自動でdescriptionなどを生成する機能があるのですが、現状安定していません。
手動で指定することも可能ですが、コードエディタに活用できるわけでもないため、JSDocのような定義をストーリー側に書きたいケースはあまりなさそうです。
Storybookのドキュメント機能はコンポーネントと同時に掲載できる点はメリットなのですが、JSDocからの抽出対象が狭いため、完全に統合することが難しい状況です。ストーリーを記述する範囲でコメントを付加する程度にとどまり、APIドキュメントは別途JSDocで管理することになりそうです。
ローカルサーバー
npx start-storybook
コマンドでローカルサーバーが起動します。起動時にアドレスがコンソール出力され、ブラウザからアクセス可能です。/index.html
は明示的に指定する必要があるでしょう。
起動前にビルドが失敗した場合は、修正して再実行します。初回セットアップ時にはconfigが完備していないケースもあるため、サンプルのストーリーを一度起動して動作確認まで終えておいた方が良いでしょう。
スタティックビルド
npx build-storybook -o dist/
コマンドで一式ビルドも可能です。-o
オプションのディレクトリにhtml, javascriptが出力されます。
ブラウザで直接index.html
ファイルを表示可能なほか、別途HTTPサーバーで配信できます。
なお、ビルド失敗時にはエラー出力しますが、build-storybookのログは判別不能なため、start-storybookでビルドが通る状態を完備しておく必要があるでしょう。
まとめ
StorybookはUIコンポーネントに変数を入力して表示させる手法で品質確認するツールです。SPAなどの場合、バックエンドAPIほか特殊な環境を必要とするケースが多くなりがちですが、設計しだいでUIのみテスト可能にできます。
眺めることによる確認のほか、異常値を入力することによる堅牢性テストなどもStorybookのメリットと言えます。
セットアップについては、限られた特定条件では設定不要で利用開始できますが、基本的にはWebpackとBabelについて理解したうえでStorybookのconfigレイヤを把握することになるでしょう。
Chuma Takahiro