Posted at

Storybookの新しいアドオン addon-docs がいい感じ

Storybookのv5.2 で入る予定の新しいアドオン addon-docs を試してみたら、なかなかいい感じだったので布教記事を書きます。

image.png

実物はGitHub Pagesで公開しています。

https://y-takey.github.io/storybook_docs_example/

(リポジトリ: https://github.com/y-takey/storybook_docs_example )

addon-docs は (既存のアドオンである) addon-info をほぼ置き換える新しいアドオンで、従来のストーリー形式に加えて MDXも使えることが一番の特徴だと思います。上の画像のようなドキュメントを手軽に書くことができます。

MDXを使えることが理由で、 StyleguidistDocz を選んだ人もいるんじゃないかと思いますが、これからは Storybook も負けていません。


※ 本記事は Storybook および addon-docs のバージョン 5.2.0-alpha.29 を元にしており、最新バージョンでは設定や使用方法が変わっている可能性がありますのでご注意下さい。


設定方法など

Storybook自体のインストール・設定は終わっている前提で、addon-docs のインストール・設定等は次のとおりです。


Storybook 本体と既存アドオンのアップグレード

2019/06/23 時点では Storybook@5.2 はまだ正式リリースされていないため、debug を指定してアップグレードします。

yarn upgrade @storybook/react@debug @storybook/addons@debug @storybook/addon-actions@debug

他にも使用している公式アドオンがあれば同様にアップグレードしてください。


addon-docs 等のインストール

yarn add -D @storybook/addon-docs@debug @storybook/source-loader@debug

addon-docs の他に、ソースも表示できるようにするために @storybook/source-loader もインストールしています。

ソース表示が不要な場合はインストールしなくても大丈夫です。


addon-docs の設定など


.storybook/config.js

import { load } from '@storybook/react';

load(require.context('../src', true, /\.stories\.[tj]sx?$/), module);
load(require.context('../src', true, /\.stories\.mdx$/), module);


ロード対象ファイルの正規表現は適宜変えて下さい。この例では TypeScript , mdx をロードするようにしています。

今回はMDXのみとするので書いていませんが、以下の設定を上の config.js に追加すると、従来のストーリにも自動で(ある程度よしなに)ドキュメントを追加してくれます。


.storybook/config.js

import { addParameters } from '@storybook/react'

import { DocsPage } from '@storybook/addon-docs/blocks';

addParameters({
docs: DocsPage,
});



.storybook/presets.js

module.exports = [

'@storybook/addon-docs/react/preset',
];


.storybook/webpack.config

const path = require('path');

module.exports = ({ config }) => {
config.module.rules.push({
test: /\.stories\.[tj]sx?$/,
use: [
{
loader: require.resolve('@storybook/source-loader'),
options: { injectParameters: true },
},
],
include: [path.resolve(__dirname, '../src')],
enforce: 'pre',
}, {
test: /\.(ts|tsx)$/,
use: [
{
loader: require.resolve('awesome-typescript-loader'),
},
{
loader: require.resolve('react-docgen-typescript-loader'),
},
],
include: [path.resolve(__dirname, '../src')],
});
config.resolve.extensions.push('.ts', '.tsx');

return config;
};


ソースコードを表示するには @storybook/source-loader が必要となるため、 webpack.config に設定を追加します。(module.rules.push の1つ目の引数)

また TypeScript のソースコードから props のテーブルを表示するには react-docgen-typescript-loader が必要となるため、こちらもwebpack.config に設定を追加します。(module.rules.push の2つ目の引数)

ここでは awesome-typescript-loader を使っていますが、 ts-loader でも大丈夫です。ちなみに、TypeScriptまわりの設定については、 @storybook/preset-typescript を使えばwebpackの設定を自分でやる必要はありません。(内部では ts-loader, react-docgen-typescript-loader を追加してくます)

また、TypeScriptの他にも prop-types, flowでも props のテーブルを表示してくれます。(それぞれの対応する loader の設定が必要)


MDX

ドキュメントは以下のような感じで書きます。(MDXのハイライトがないみたいで、ちょっと見にくいかもしれません。)


Button.stories.mdx

import { action } from "@storybook/addon-actions";

import { Story, Meta, Preview, Props, Source, Description } from "@storybook/addon-docs/blocks";

import Button from "./Button";

<Meta title="hoge" parameters={{ component: Button }} />

# Button

何の変哲もない、ただのボタン。

<Source code={`import Button from "~/components/Button";`} />

<Preview withSource="open">
<Story name="basic" >
<Button label="this is src" onClick={action('clicked')} />
</Story>
</Preview>

<Props of="." />


@storybook/addon-docs/blocks から import できるコンポーネントは以下のものがあります。


Meta


Props

プロパティ
必須
説明

title
必須
サイドバーに表示されるタイトル。"¦"(縦棒)でセクショニングできて、"/"で階層化できる。(たぶん addon-info と同じ記法)

decorators
任意(デフォはなし)

addon-info と同様なため詳細はそちらを参照。指定する場合は1つでもdecoratorの配列にする必要がある。

parameters
任意(デフォはなし)

{ component, notes, info } のオブジェクトでいずれも任意要素。後述の Props, Description 等のコンポーネントから参照される。


<Meta

title="セクションA|Components/Button"
parameters={{
component: Button,
notes: "This is notes;",
info: "This is info.",
}}
/>


Preview


Props

プロパティ
必須
説明

withSource
任意(デフォは"closed")
ソースも一緒に表示するかの設定で、"open"


<Preview withSource="open">

<Story name="basic" >
<Button label="this is src" onClick={action('clicked')} />
</Story>
</Preview>

image.png


Story


Props

プロパティ
必須
説明

id
任意
他の箇所でidを指定して参照できるようになる。

name
任意
サイドメニューに表示される名称

height
任意
表示領域の高さ


<Story name="basic" >

<Button label="this is src" onClick={action('clicked')} />
</Story>


Source


Props

プロパティ
必須
説明

code
必須
表示するソースコード

language
任意(デフォは"jsx")
ハイライト用に使われる言語。


<Source code={`import Button from "~/components/Button";`} />

image.png


Props


Props

プロパティ
必須
説明

of
必須
対象のコンポーネント。"." でカレントコンポーネント(Metaコンポーネントの parameters.component )


<Props of={Button} />

// <Props of="." /> と書いても同じ

image.png


Description


Props

プロパティ
必須
説明

of
任意
対象のコンポーネント。"." でカレントコンポーネント。

markdown
任意
表示するマークダウンテキスト。

type
任意
"info", "notes", "docgen", "auto" のいずれかを指定可能。"info", "notes" は Meta コンポーネントの parameters プロパティで指定した 同名の要素を使用する。"docgen" は各種のdocgen loader によって注入される 対象コンポーネントの __docgenInfo.description を使用する。

markdown が指定されている場合には type は無視される。


<Description markdown="**BOLD**" />

<Description type="info" />

image.png


その他

Storybook は React 以外にも Vue や Angular 等など色々サポートしていますが、 addon-docs が対応しているのは現時点では React, Vue だけです。( Vue は一部未実装の模様)

Angularも今後対応予定のようです。


説明は以上です。まだまだドキュメントがほとんどないため addon-docs のソースコードも読みながら調べた内容をまとめてみました。

正式リリースされる際にはきっとドキュメントも整備されていると思います。