この記事は Angular + Storybook でコンポーネントガイドを作ろう を参考に、インストールのコマンドや設定をメモしたものです。

Storybook
https://storybook.js.org/

環境

  • macOS High Sierra
  • yarn v1.6
  • node v8.10
  • @storybook/angular v3.4.3
  • @angular/cli v1.7.4

Storybook のインストール

npm / yarn どちらでもインストールできます。両方試した結果 yarn のほうがスムーズだったため、こちらを使う事にしました。

私の環境には yarn がインストールされていなかったため homebrew で入れました。

$ brew install yarn

一発目はエラーで失敗したのでリトライ。

xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools),
missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun
Error: Failure while executing: git config --local --replace-all homebrew.private true

$ xcode-select --install
$ xcode-select: note: install requested for command line developer tools

$ brew install yarn
$ which yarn

/usr/local/bin/yarn

まず Angular のプロジェクトを作成します。

$ ng new learn-storybook
$ cd learn-storybook

Storybook のコマンドラインツールをインストールします。

$ yarn add @storybook/cli

【参考】 node 9系だと SyntaxError: Unexpected token ( in JSON at position 0 というエラーでコマンドが完了しなかったので、node 8 (npm 5.6) を使う事にしました。

Storybook の Angular プラグイン的なものをインストールします。

$ yarn add @storybook/angular babel-core

Storybook を作成します。

$ yarn run getstorybook

# デモページで使われるアドオンもインストール
$ yarn add @storybook/addon-notes 
$ yarn add @storybook/addon-links
$ yarn add @storybook/addon-actions

package.json を開くと storybook / build-storybook という2つのスクリプトが追加されています。Storybook の設定は .storybook ディレクトリに配置されるため、このディレクトリが読み込まれるよう設定します。

- "storybook": "start-storybook -p 6006",
+ "storybook": "start-storybook -p 9001 -c .storybook",
"build-storybook": "build-storybook"

Storybook のファイルが ng serve の実行を妨げないように設定を追加します。

// src/tsconfig.app.json

{
+  "exclude": [
+    "stories",
+    "**/*.stories.ts"
+  ]
}

これでインストールは完了です。
Storybook を起動してデモページを開いてみましょう。

$ yarn run storybook

ブラウザで http://localhost:9001 を開き Welcome to storybook が表示されていれば成功です。表示が確認できたら Ctrl + C で終了します。

スクリーンショット 2018-04-30 21.57.27.png

Storybook にコンポーネントを追加

デモページにはあらかじめいくつかのコンポーネントが表示されています。自分で作ったコンポーネントを追加してみましょう。

まず適当なコンポーネントを作成します。

$ ng generate hello-button
// src/app/hello-button/hello-button.component.ts

import { 
+ Input,
  Component, 
+ EventEmitter,
  OnInit,
+ Output,
} from '@angular/core';

@Component({
  selector: 'app-hello-button',
  templateUrl: './hello-button.component.html',
  styleUrls: ['./hello-button.component.css']
})
export class HelloButtonComponent implements OnInit {
+  @Input() name: string;
+  @Output() hello = new EventEmitter<string>();

  constructor() { }

  ngOnInit() {
  }

+  click() {
+    this.hello.emit(`Hello ${this.name}`);
+  }

}
// src/app/hello-button/hello-button.component.html

- <p>
-  hello-button works!
- </p>

+ <button type="button" (click)="click()">
+ Hello {{name}}!
+ </button>

こんな感じのコンポーネントです。

<hello-button name="foo"></hello-button>
  • <button>Hello foo!</button> のように展開される
  • クリックすると hello イベントが発火し Hello foo! を受け取る事ができる

ストーリーの作成とコンポーネント追加

Storybook のソースコードは index.stories.ts に記述されています。
ここに hello-button コンポーネントを追加してみます。

// src/stories/index.stories.ts

+ import { HelloButtonComponent } from '../app/hello-button/hello-button.component';

+ storiesOf('Hello Button', module)
+   .add('with name', () => ({
+     component: HelloButtonComponent,
+     props: {
+       name: 'foo',
+     },
+   }))
;

storiesOf は Storybook に新しいストーリー Hello Button を追加し、add はストーリーにコンポーネントを追加します。props には @Input に値を渡すための key/value を記述します。

再び Storybook を起動してみましょう。
Hello Button という見出しが追加され、展開すると with name というタイトルが現れるはずです。

$ yarn run storybook

スクリーンショット 2018-04-30 22.19.29.png

コンポーネントのイベントを拾う

hello-button コンポーネントは hello イベントを発火する機能を持っています。
Storybook で発火したイベントを拾ってみましょう。

// src/stories/index.stories.ts

storiesOf('Hello Button', module)
  .add('with name', () => ({
    ...
  }))
+ .add('with action', () => ({
+   component: HelloButtonComponent,
+   props: {
+     name: 'bar',
+     hello: action('clicked!')
+   },
+ }))

ソースコードを保存するとブラウザが自動でリロードし、Hello Button の見出しの下に with action というタイトルが現れます。

ボタンをクリックするとページ下部の ACTION LOGGER タブに clicked! が表示されます。

1.gif

ACTION LOGGER への出力

Storybook にはいろいろなアドオンが存在します。Angular のデモページはデフォルトで actions / links / notes の3つのアドオンが読み込まれています。

// .storybook/addons.js

import '@storybook/addon-actions/register';
import '@storybook/addon-links/register';
import '@storybook/addon-notes/register';
// src/stories/index.stories.ts

import { withNotes } from '@storybook/addon-notes';
import { action } from '@storybook/addon-actions';
import { linkTo } from '@storybook/addon-links';

actions アドオンをインポートすると action 関数を利用できます。
action 関数は受け取った引数を ACTION LOGGER タブに出力します。

さきほどソースコードに追加したこの部分ですね。

props: {
  hello: action('clicked!')
}

NOTE への出力

notes アドオンを利用すると NOTE タブに任意の HTML を出力する事ができます。

// src/stories/index.stories.ts

storiesOf('Hello Button', module)
  .add('with name', () => ({
    ...
  }))
+  .add('with note', withNotes(`
+    <h3>Notes</h3>
+    <span>sample text</span>
+    `)(() => ({
+      component: HelloButtonComponent,
+      props: {
+        name: 'hoge',
+      },
+    })
+  ))

スクリーンショット 2018-04-30 22.50.10.png

アドオンの追加

デフォルト以外のアドオンを読み込んでみましょう。
Knobs を利用すると Storybook 上で入力したテキストをリアルタイムにコンポーネントに反映させる事ができます。

$ yarn add @storybook/addon-knobs
// .storybook/addons.js

+ import '@storybook/addon-knobs/register';
// src/stories/index.stories.ts

+ import { text, withKnobs } from '@storybook/addon-knobs/angular';

storiesOf('Hello Button', module)
+ .addDecorator(withKnobs)
  .add('with name', () => ({
    ...
  }))
  .add('with name', () => ({
    component: HelloButtonComponent,
    props: {
-     name: 'foo',
+     name: text('name', 'foo')
    },
  }))

ブラウザをリロードすると追加の Knobs アドオンが有効になります。

1.gif

他にもいろいろなアドオンが Storybook 公式ページで紹介されています。

Storybook Addon Gallery
https://storybook.js.org/addons/addon-gallery/

静的ページの出力

build-storybook コマンドを使うと Storybook を静的ページとして出力する事ができます。出力先はルートディレクトリ直下の storybook-static です。

$ yarn run build-storybook
$ open storybook-static/index.html

ディレクトリ構成

Storybook は既存の Angular プロジェクトに後付けで追加する事もできます。Storybook によって追加されるディレクトリ・ファイルは以下に示す ●印 の部分です。

├── .storybook ●
│   ├── addons.js ● // アドオン
│   └── config.js ● // Storybook の読み込み
├── node_modules
├── package.json
├── src
│   ├── app
│   ├── stories ●
│   │   └── index.stories.ts ● // Storybook を記述するファイル
├── storybook-static ● // build-storybook で出力される静的ページ
│   ├── favicon.ico ●
│   ├── iframe.html ●
│   ├── index.html ●
│   └── static ●

おわり

複数プロジェクトで利用するオリジナルのコンポーネントを開発しているのですが、使い方を説明するために demo.html にサンプルを載せて GitHub wiki にドキュメントを書いて...という事をせっせと行っていました。これを便利に代行してくれるのが Storybook ではないかと思います。

まだ Angular 未対応のアドオンもちらほらあるようですが、demo.html みたいな泥臭い作業をせっせとこなすより、新しいものをワクワクしながら使いたいですね!

Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.