[Storybook] UI Component 管理ツールの紹介

はじめに

オハコンバンニチハ、モバイルアプリサービス部の清田です。

UI Component 管理ツールの Storybook がメジャーバージョンアップし バージョン5 になりましたー!パチパチ。 今回は、Storybook の魅力と導入についてご紹介できればと思います。

Storybookとは?

Storybookは、UI Component 管理・開発環境を提供するオープンソースのツールです。

storybook

主な用途としては以下な感じです。

  • デザインスタイルガイド
  • コンポーネントの挙動確認
  • UIコンポーネント仕様、画面仕様の確認など

Webフロントエンド界隈で主要なフレームワークに対応しているので、ご利用できる範囲も広い印象です。

  • React
  • Vue
  • Angular

そして、サンフランシスコに拠点を置く、Chroma Software 社がツールの主な運営のもと、 世界中の有志のコントリビューターさん達によって維持されているみたいです。

ちなみにツールのデザインを担当されたのが、Dominic Nguyen(@domyen)さんとのこと。

ありがたやー。

おしながき

今回はお仕事でお世話になっている React x TypeScript 構成を想定し、Storybook環境構築してみたいと思います。

実行環境について

今回の導入に際して、環境情報を以下に記載します。

  • OS: macOS Mojave v10.14 ++
  • NodeJS: v10.13.0 ++
  • npm: v6.4.1 ++
  • yarn: v1.12.3 ++

ディレクトリ構成

ディレクトリ構成について、デファクトな create-react-app でもいいのですが、今回は自分のお好みの構成で構築できればなと。 今回はこんな感じになっています。

┣ internals
┃  ┣ storybook/
┃  ┃  ┣ addons.js 
┃  ┃  ┣ config.js
┃  ┃  ┗ webpack.config.js
┃  ┗ tsconfig/
┃     ┗ tsconfig.storybook.json
┣ src
┃  ┗ Example/
┃     ┗ index.stories.tsx
┣ .babelrc
┗ package.json

パッケージのインストール

それではStorybookを利用するための環境を構築していこうと思います。 以下コマンドから、package.jsonを作成します。

yarn init

続いて、各パッケージをインストールしていきます。

React

UIコンポーネント用のフレームワークとして利用します。

yarn add react react-dom
yarn add -D @types/react @types/react-dom

Typescript

開発言語はTypescriptを利用します。

yarn add -D typescript ts-loader

Storybook & path

本題のstorybook関連のパッケージをインストールします。 storybookは各ライブラリ向けのパッケージを用意してくれているので今回はReact用のパッケージを利用します。

yarn add -D @storybook/react \
@types/storybook__react \
react-docgen-typescript-webpack-plugin \
path

ここまでで大体のパッケージはそろったのですが、 @storybook/react 追加後、以下のワーニングがでるのでbabel関連のパッケージもインストールしておきます。

warning " > @storybook/react@5.0.8" has unmet peer dependency "babel-loader@^7.0.0 || ^8.0.0".
warning "@storybook/react > @babel/plugin-transform-react-constant-elements@7.2.0" has unmet peer dependency "@babel/core@^7.0.0-0".

...


Babel

yarn add -D @babel/core \
@babel/preset-env \
babel-loader

設定ファイルの作成

パッケージのインストールが済んだので、各設定ファイルを作成していこうと思います。

.babelrc

今回は直接関係ないですが、以下の設定を定義します。

{
  "presets": ["@babel/env", "@babel/react"]
}

webpack

Storybookは内部でwebpackを利用しています、その設定ファイルを定義します。

# internals/storybook/webpack.config.js

// ファイル指定関連
const fs = require('fs')
const path = require('path')

// docgen関連パッケージ読み込み
const TSDocgenPlugin = require('react-docgen-typescript-webpack-plugin')

// ディレクトリ指定用関数
const appDirectory = fs.realpathSync(process.cwd())
const resolveApp = relativePath => path.resolve(appDirectory, relativePath)

module.exports = {
  module: {
    rules: [
      {
        test: /\.(ts|tsx)$/,
        loader: 'ts-loader',
        exclude: /node_modules/,
        include: resolveApp('src'),
        options: {
          configFile: `${resolveApp(
            'internals/tsconfig'
          )}/tsconfig.storybook.json`,
        },
      },
    ],
  },
  resolve: {
    extensions: ['.ts', '.tsx'],
  },
  plugins: [new TSDocgenPlugin()],
}

tsconfig

今回のtsconfig設定情報はStorybook公式サイトから拝借してみました。

# internals/tsconfig/tsconfig.storybook.json

{
  "compilerOptions": {
    "module": "commonjs",
    "target": "es5",
    "lib": ["es5", "es6", "es7", "es2017", "dom"],
    "sourceMap": true,
    "allowJs": false,
    "jsx": "react",
    "moduleResolution": "node",
    "forceConsistentCasingInFileNames": true,
    "noImplicitReturns": true,
    "noImplicitThis": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "suppressImplicitAnyIndexErrors": true,
    "noUnusedLocals": true,
    "declaration": true,
    "allowSyntheticDefaultImports": true,
    "experimentalDecorators": true
  },
  "include": ["../../src/**/*"],
  "exclude": ["../../node_modules"]
}

config.js

Storybookの設定情報を以下のファイルに記載します。
今回は指定した .stories.tsx 拡張子を取得する設定を記述しています。

# internals/storybook/config.js

import { configure } from "@storybook/react";

const req = require.context("../../src", true, /.stories.(ts|tsx)$/);

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

configure(loadStories, module);

package.json

最後にpackage.json側に実行コマンドを定義します。

指定オプション
- -p ポート番号の指定
- -c storybookの設定ファイル先指定

# package.json

{
  ...
  "scripts": {
    "storybook": "start-storybook -p 9001 -c ./internals/storybook",
  },
  ...
}

Storybookの実行

最低限の環境設定ができたのでStorybookを起動してみたいと思います。
以下コマンドから正常に起動できると、http://localhost:9001/からアクセスできるようになります。

yarn storybook

...

╭─────────────────────────────────────────────────╮
│                                                 │
│   Storybook 5.0.8 started                       │
│   5.98 s for manager and 7.12 s for preview     │
│                                                 │
│   Local:            http://localhost:9001/      │
│   On your network:  http://192.168.0.5:9001/    │
│                                                 │
╰─────────────────────────────────────────────────╯

現時点では表示するコンポーネントを定義していないので、以下画面が表示すれば成功です。

storybook

Storybook 定義ファイル作成

Storybookを構成する定義ファイルを作成してみたいと思います。 src ディレクトリー配下に .stories.tsx 拡張子のファイルを作成します。

# src/Example/index.stories.tsx

import * as React from "react";
import { storiesOf } from "@storybook/react";

storiesOf("Example", module).add("List item", () => <div>Hello :-)</div>);

  • (1) storiesOfメソッドの引数にコンポーネントディレクトリの名称を指定
  • (2) addメソッドの第1引数にコンポーネントサブディレクトリの名称を指定
  • (3) addメソッドの第2引数に描画するコンポーネントを指定

storybook

Storybookの構成

Storybookでコンポーネントを描画するところまではできました。 それでは、Storybookの画面構成についてかるく触れればと思います。

storybook

  • Aエリア
    • Storybook内で定義してある各コンポーネント間を遷移するナビゲーションになります。
  • Bエリア:
    • Storybook内のメインであるUIコンポーネントを描画するエリアになります。
  • Cエリア:
    • 今回はふれませんでしたが、StorybookはAddonといった拡張機能が描画されるエリアになります。

ナビゲーションエリアのツール紹介

以下の箇所を選択すると、Storybookのショートカットを確認できます。

storybook

以下の箇所からUIコンポーネントのキーワード検索が可能です。

storybook

コンポーネント描画エリアのツール紹介

以下の各ボタンにて表示系の操作が行えます。

storybook

  • A: 拡大表示
  • B: 縮小表示
  • C: 拡大・縮小を初期表示
  • D: グリッド表示
  • E: 全画面表示
  • F: 別画面表示

アドオンエリア

Storybookを有効的に使うためにはAddon機能は必要不可欠であったりします。 ちょっと今回はアドオン機能についての話しが長くなってしまうため次回アドオン機能の利用方法等ご紹介できればと思います。

まとめ

Storybookの環境構築についてご紹介いたしました。
昨年からメジャーバージョンが続いており活発に開発されている印象です。もし開発中のプロダクトでUIコンポーネントの管理に課題を感じている際はご検討してみてはいかがでしょうか?

おまけ Storybook Docs の紹介

自分のチームではStorbookをUIコンポーネントのデザインガイドラインや画面仕様的なドキュメンテーションに重きを置いた用途で利用を進めているのですが、つい先日 Storybook Docs なるアドオンがアナウンスされました。 まだ利用はできないのですが、MDX(Markdown中にJSXを埋め込めちゃうやつ)がサポートしてくれてるとか要チェックなアドオンです。