y-ohgi's blog

TODO: ここになにかかく

Next.js / TypeScript のプロジェクトStorybook を導入する

f:id:y-ohgi:20210615153002p:plain

TL;DR

  • Storybook はUI コンポーネント単位でプレビューできるツール
  • Storybook をNext.js / TypeScript (/ material-ui / docker-compose) のプロジェクトに導入をする

概要

version

  • TypeScript
    • 4.0
  • Next.js
    • 10.1.3
  • Storybook
    • 6.2

Story Book

Storybook: UI component explorer for frontend developers

コンポーネント単位でプレビューを行うことができるようになるツール。
React に限らず、vue やEmber など、モダンなフロントエンドでだいたい使える。

Introduction to Storybook

はじめる

StoryBook のインストール

まずはStory Book を既存のプロジェクトへインストールを行うところから。

$ npx sb init --react

5分ほどかかりインストール完了。package.json へ起動コマンドも勝手に書いてくれる

$ git diff package.json
diff --git a/package.json b/package.json
index e89a2c8..7037f78 100644
--- a/package.json
+++ b/package.json
@@ -5,7 +5,9 @@
     "dev": "npm i && next -p $PORT",
     "build": "next build",
     "start": "next start -p $PORT",
-    "type-check": "tsc"
+    "type-check": "tsc",
+    "storybook": "start-storybook -p 6006",
+    "build-storybook": "build-storybook"
   },

  :

   "devDependencies": {
+    "@babel/core": "^7.14.6",
+    "@storybook/addon-actions": "^6.2.9",
+    "@storybook/addon-essentials": "^6.2.9",
+    "@storybook/addon-links": "^6.2.9",
+    "@storybook/react": "^6.2.9",
     "@types/node": "^12.20.7",
     "@types/react": "^17.0.3",
     "@types/react-dom": "^17.0.3",
     "@types/react-swipeable-views": "^0.13.0",
+    "babel-loader": "^8.2.2",

起動してみる

docker-compose で使うのでhost に公開してあげるために、 --host オプションを指定。
ローカルにランタイムが入っている場合は無視して下しあ。

-    "storybook": "start-storybook -p 6006",
+    "storybook": "start-storybook -p 6006 -h 0.0.0.0",

docker-composes.yaml

+  storybook:
+    build: .
+    ports:
+      - 6006:6006
+    volumes:
+       - .:/app:delegated
+       - /app/.next
+    command: npm run storybook
$ docker-compose up

そこそこ長い起動時間の後この画面へ

Example-Introduction-Page-⋅-Storybook.png

プレビューしてみる

Storybook のパスを設定する

Next.js を相対パスではなく絶対パスで使用していると、Storybook が解決できないです。
そのため、Storybook のコンフィグにパスを再設定するよう追記してあげます。

.storybook/main.js

const path = require('path');

module.exports = {
  "stories": [
    "src/**/*.stories.@(mdx|tsx)",
  ],
  "addons": [
    "@storybook/addon-links",
    "@storybook/addon-essentials"
  ],
  webpackFinal: async (config, { configType }) => {
    config.resolve.modules = [
      path.resolve(__dirname, ".."),
      "node_modules",
    ]
    return config;
  }
}

とりあえず出してみる

とりあえず何の引数も取らないボタンコンポーネントをプレビューしてみることに。

プレビューしたいコンポーネントと同じディレクトリで button.stories.tsx のように書くことがお作法っぽいので、とりあえず横に配置していく

src/components/atoms/buttons/shareButton.stories.tsx

import React from 'react';
import { Story, Meta } from '@storybook/react';

import ShareButton from './shareButton';

export default {
  title: 'ShareButton',
  component: ShareButton,
} as Meta;

const Template: Story = () => <ShareButton />;

export const Default = Template.bind({});

f:id:y-ohgi:20210615152629p:plain

material-ui 対応

そのままだとmaterial-ui のテーマが反映されません。当たり前ですね。
なのでmaterial-ui 用のアドオンがあるので導入していきます。

といっても簡単で、 storybook-addon-material-ui をインストールして .storybook/preview.js を書き換えるだけでおしまいです

$ npm i storybook-addon-material-ui --save-dev

.storybook/preview.js

import { muiTheme } from 'storybook-addon-material-ui'

import theme from '../src/styles/theme'

export const decorators = [
    muiTheme([theme])
];

余談

パス周りがめんどうなものの、かんたんにコンポーネントを表示できるのはなかなか体験が良いですね。
コンポーネントの切り方みたいなものもちゃんと意識しないと .stories.tsx ファイルを作るのが難しくなり、ベンチマーク的にも使えるのかなと思ったりしました。

参考