Help us understand the problem. What is going on with this article?

Storybook V5+React+TypeScriptで環境構築

More than 1 year has passed since last update.

alt
StorybookのV5.0がリリースされました。

Storybook+React+TypeScriptで試してみたので、内容をまとめてみました。
インストールからサンプルのコンポーネント作成と、GitHub Pagesへのデプロイまで記載しています。

まだドキュメントが古いものも多く、試行錯誤しながらでしたが、V4までと比べてTypeScript周りの設定が楽になった気がします。

なお、手順はNode.jscreate-react-appはインストール済みの前提です。

ソース
デモ


2019/03/09追記

  • @storybook/addon-consoleを追加
  • *.stories.jsもストーリの対象に追加
  • src/stories/*jsjsxはストーリ対象とするように修正
  • withInfoをaddDecoratorで指定するように変更

土台の作成

まず、create-react-appでプロジェクトを作成します。

create-react-app storybook-react-ts --typescript

作成したら、Storybookを登録して初期化処理を実行します。

cd storybook-react-ts
yarn add -D @storybook/cli
yarn sb init

実行すると、Storybookの設定が入ったフォルダとストーリーのサンプルが追加されています。

.storybook/
  addons.js
  config.js
src/stories/
  index.js

また、package.jsonにStorybookの起動とビルドのコマンドが追加されます。

package.json
  "scripts": {
    ~
    "storybook": "start-storybook -p 9009 -s public",
    "build-storybook": "build-storybook -s public"
  }

yarn storybookとコマンドを入れると、Storybookの画面が開きます。
storybook-react-ts-01.png

とりあえずこれで使えるようになりしたが、アドオンを追加したりストーリーをTypeScriptで作成できるようにしていきます。

カスタマイズ

使いやすくするため、以下の作業を行っていきます。

  • アドオン登録
    • addon-knobs プロパティを変更できる画面を追加
    • addon-viewport ビューポートを切り替えるボタンを追加
    • addon-storysource ストーリーのソースを表示
    • addon-info ストーリーの例とか説明を追加
    • react-docgen-typescript-loader TypeScriptの型からコンポーネントのプロパティ説明を追加
    • addon-console Actionsタブにコンソールログを表示する
  • ストーリーをTypeScriptで作成できるように
  • *.stories.tsxのファイル名でストーリーを作成できるように

アドオン追加

yarn add -D @storybook/addon-knobs \
  @storybook/addon-viewport \
  @storybook/addon-storysource \
  react-docgen-typescript-loader \
  @storybook/addon-info \
  @storybook/addon-console

型定義追加

yarn add -D @types/storybook__react \
  @types/storybook__addon-info \
  @types/storybook__addon-actions \
  @types/storybook__addon-knobs

Storybookの設定変更

パッケージの登録が終わったら、Storybookの設定に定義を追加していきます。

.storybook/addons.js
import '@storybook/addon-actions/register';
import '@storybook/addon-links/register';
import '@storybook/addon-knobs/register';
import '@storybook/addon-viewport/register';
import '@storybook/addon-storysource/register';
import '@storybook/addon-console';

次に、.storybook/webpack.config.jsのファイルを作成し、
TypeScriptのソースをアドインに渡す処理を追加します。

.storybook/webpack.config.js
const path = require("path");
module.exports = ({ config }) => {
  config.module.rules.push({
    test: /\.(ts|tsx)$/,
    use: [
      {
        loader: require.resolve("react-docgen-typescript-loader")
      },
      {
        loader: require.resolve('@storybook/addon-storysource/loader'),
        options: { parser: 'typescript' }
      }
    ]
  });
  config.resolve.extensions.push(".ts", ".tsx");
  return config;
};

次は、コンソールログをActionsタブに表示する処理と、TypeScriptで作成したストーリーを読み込む処理を追加します。

.storybook/config.js
import { configure } from '@storybook/react';
import { setConsoleOptions } from '@storybook/addon-console';

setConsoleOptions({
  panelExclude: []
});

function loadStories() {
  let req = require.context("../src/stories", true, /.(tsx|js)$/);
  req.keys().forEach(filename => req(filename));

  req = require.context("../src", true, /.stories.(tsx|js)$/);
  req.keys().forEach(filename => req(filename));
}

configure(loadStories, module);

コンポーネント作成

サンプルのコンポーネントを作成します。

src/component/Example/index.tsx
import React, { useState, useCallback } from "react";

export interface ExampleProps {
  /** 表示するテキスト */
  text: string;
  /**
   * true: テキスト表示 false: テキスト非表示
   * @default false
   */
  flag?: boolean;
  /** ボタンを押した時のイベントハンドラ */
  action(): void;
}

const Example = (props: ExampleProps) => {
  const { text, flag, action } = props;
  const [count, countChg] = useState(0);
  const countUp = useCallback(() => countChg(prev => prev + 1), []);
  const countDown = useCallback(() => countChg(prev => prev - 1), []);

  return (
    <div>
      {flag && <p>{text}</p>}
      <button onClick={action}>ボタン</button>
      <p>count:{count}</p>
      <button onClick={countUp}>+</button>
      <button onClick={countDown}>-</button>
    </div>
  );
};

export default Example;

addon-knobs等のデモ用に、適当なプロパティを作っています。
また、Reactの最新版に対応しているかを確認するためReact Hooksを使ってます。
プロパティの定義にはコメントを入れておけばストーリに表示されるので、適当に入れておきます。

ストーリー(TypeScript)追加

作成したコンポーネントに対応するストーリーを、登録したアドオンも使用して作成します。

src/components/Example/index.stories.tsx
import React from "react";

import { storiesOf } from "@storybook/react";
import { withInfo } from "@storybook/addon-info";
import { withKnobs, text, boolean } from "@storybook/addon-knobs";
import { action } from "@storybook/addon-actions";

import Example from "../Example";

const components = storiesOf("Components", module);
components
  .addDecorator(withKnobs)
  .addDecorator(withInfo({ inline: true }))
  .add("Example", () => (
    <Example
      text={text("テキスト", "ああああ")}
      flag={boolean("テキスト表示", true)}
      action={action("ぽちっとな")}
    />
  ));

yarn storybookとコマンドを入れると、Storybookの画面が開きます。

storybook-react-ts-02.png

GitHub Pagesに登録

デプロイ用のツールを登録します。

yarn add -D gh-pages

登録したら、起動コマンドを追加します。

package.json
  "scripts": {
    ~
    "predeploy": "build-storybook",
    "deploy": "gh-pages -d storybook-static"
  }

predeployはデプロイ前の自動ビルドの設定、deployではbuild-storybookで出力されるフォルダstorybook-staticを指定します。

デプロイ実行はyarn deployです。
完了すると以下のアドレスにデプロイされます。

https://XXXXX.github.io/storybook-react-ts

デプロイ時に作成されたファイルは不要だと思うので、.gitignoreに登録しておきます。

.gitignore
/storybook-static
otanu
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away