Vite + React + TypeScript に Vite 用 Storybook を導入する。Storybookは必要だぞ☆
はじめに
ごめんなさい。懺悔します。
ストーリーブック使ったことがないし、メンバーも少ないし、他に必要なライブラリがいっぱいあって、その使い方とかも調べないといけないし、そろそろ開発も進めないと進捗もやばいし、
正直ストーリーブックまで用意しなくてもよくね?と思ってました。
ぶっちゃけもうメンドウだし、別になくても開発に困らんでしょと。
だから必要なライブラリは大方いれたし、ストーリーブックなしで開発進めちゃいました。
そしたらすぐ気付いたんです。こまごました汎用的なコンポーネント作りだしたらね、
あれ?もしかしてこれってストーリーブックないほうがメンドイんじゃない!?
自分が間違ってました。もう本当ごめんなさい。
というわけで、今回は Vite で作成した React アプリケーションに Vite 用の Storybookを導入する方法です。
つまづきポイントは1か所です。
Storybook
Storybook は、UIのカタログを作るツールで、個別のコンポーネント単体の動作・UIの確認ができます。
つまりコンポーネントにどんな機能があるのか?どんな使い方をするのか?といったUIの説明書みたいなものです。
UI仕様書としてメンバーと共有できるのはもちろん、自分は忘れっぽいのでメモ的にも必要。
その上、コンポーネントを作っている最中はテストにも使えるという、絶対に必要というわけではないけど、あると便利な非常にすぐれたツールです。
Vite 用には「@storybook/builder-vite」を使用します。
@storybook/builder-vite のインストール
まずは storybook init
コマンドを実行することで、ウィザード形式で Storybook に必要なインストールを行ってくれます。
npx storybook init --builder @storybook/builder-vite
storybook をインストールしていいか聞かれるので y を入力します。
Need to install the following packages:
storybook
Ok to proceed? (y)
eslint-plugin-storybook をインストール していいか聞かれるので eslint を 導入しているなら y を入力します。
eslint-plugin-storybook のインストールは成功したけど、eslint の設定ができなかったとエラーになります。
サポートしている eslint の設定ファイルは .eslintrc.js か .eslintrc.cjs だけです。
eslint は、あとで自分で設定することにします。
インストールは以上で終了です。
インストールで追加されたファイル等
package.jsonを確認すると、以下のものが devDependencies で インストールされています。
"devDependencies": {
@babel/core: v7.18.0,
@storybook/addon-actions: v6.5.3,
@storybook/addon-essentials: v6.5.3,
@storybook/addon-interactions: v6.5.3,
@storybook/addon-links: v6.5.3,
@storybook/builder-vite: v0.1.35,
@storybook/react: v6.5.3,
@storybook/testing-library: v0.0.11,
babel-loader: v8.2.5,
eslint-plugin-storybook: v0.5.12,
・・・
scripts にも storybookを起動するスクリプトが追加されています。
"scripts": {
・・・
"storybook": "start-storybook -p 6006",
"build-storybook": "build-storybook"
他にも root 直下に .storybook フォルダができています。
src直下には stories フォルダができています。
動作確認
とりあえず以下のコマンドで storybook を実行してみます。
npm run storybook
storybook が起動できます。
eslint の設定
つぎは.eslintrc ファイルを設定します。
storybook の eslint 設定は ストーリファイルだけに適用させたいので、overrides で設定します。
- eslint-plugin-storybook の オススメ recommended 設定を
*.stories.@(ts|tsx|js)
にマッチするファイル(=ストーリーファイル)にのみ適用させています。
・・・
extends:
- plugin:react/recommended
- plugin:react-hooks/recommended
- airbnb
- airbnb-typescript
- prettier
overrides:
- files:
- '**/__tests__/**/*.+(ts|tsx|js)'
- '**/?(*.)+(spec|test).+(ts|tsx|js)'
extends:
- plugin:jest-dom/recommended
- plugin:testing-library/react
+ - files:
+ - '*.stories.@(ts|tsx|js)'
+ extends:
+ - plugin:storybook/recommended
ignorePatterns:
- vite.config.ts
- vitest.setup.ts
settings:
import/resolver:
typescript: []
rules:
・・・
次に src 直下の stories フォルダにある ストーリーファイルをみてみます。
-
devDependencies でインストールされた @storybook/react を import している。
ストーリーファイルは devDependencies でインストールされているライブラリをインポートする必要があるので、.eslintrc で許可するようルールを設定します。 -
デフォルトエクスポートしている。
私は通常のファイルはデフォルトエクスポートを禁止しているので、ストーリーファイルはデフォルトエクスポートを許可するようルールを設定します。
上記の2点は、各自の .eslintrc ファイルの設定によりますので、必要な場合のみルールを追記します。
import React from 'react'
+ // devDependencies でインストールされた @storybook/react を import している
+ import { ComponentStory, ComponentMeta } from '@storybook/react'
import { Button } from './Button'
// More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export
+ // デフォルトエクスポートしている
+ export default {
title: 'Example/Button',
component: Button,
// More on argTypes: https://storybook.js.org/docs/react/api/argtypes
// argTypes: {
// backgroundColor: { control: 'color' },
// },
} as ComponentMeta<typeof Button>
.eslintrc ファイルにルールを追記します。
・・・
extends:
- plugin:react/recommended
- plugin:react-hooks/recommended
- airbnb
- airbnb-typescript
- prettier
overrides:
- files:
- '**/__tests__/**/*.+(ts|tsx|js)'
- '**/?(*.)+(spec|test).+(ts|tsx|js)'
extends:
- plugin:jest-dom/recommended
- plugin:testing-library/react
+ - files:
+ - '*.stories.@(ts|tsx|js)'
+ extends:
+ - plugin:storybook/recommended
+ rules:
+ # default export を許可する
+ import/no-default-export: off
+ # devDependencies からの import を許可する
+ import/no-extraneous-dependencies: off
ignorePatterns:
- vite.config.ts
- vitest.setup.ts
settings:
import/resolver:
typescript: []
rules:
・・・
以上で eslint の設定は終了です。
eslint を実行してコードをチェックしてみましょう。
各自の eslint の設定によって、stories フォルダ内のコードでエラーが出ると思いますので、修正します。
storybook 起動ファイル .main.js の設定
つづいて root 直下の .storybook フォルダにある main.js を設定します。
この main.js が storybook 起動ファイルになります。
Storybook のビルダーはデフォルトでは vite.config.ts ファイルを読み取りません。
main.js で vite.config.ts を読み込むよう設定します。
ここがつまづきポイントです。
公式サイトに vite.config.ts を読み込む方法が記載されていますが、記載されている方法では vite.config.ts ファイル を読み込めませんでした。
こちらに記載されている方法で vite.config.ts ファイル を読み込みます。
参考:https://github.com/storybookjs/builder-vite/issues/85
- javascript ファイルだとエラーがわかりにくいので、 main.js の拡張子を main.ts に変更して Typescript ファイルにします。
- main.ts を以下のように変更します。
+ const path = require("path");
+ const { loadConfigFromFile, mergeConfig } = require('vite');
module.exports = {
"stories": [
"../src/**/*.stories.mdx",
"../src/**/*.stories.@(js|jsx|ts|tsx)"
],
"addons": [
"@storybook/addon-links",
"@storybook/addon-essentials",
"@storybook/addon-interactions"
],
"framework": "@storybook/react",
"core": {
"builder": "@storybook/builder-vite"
},
"features": {
"storyStoreV7": true
},
+ async viteFinal(config, { configType }) {
+ const { config: userConfig } = await loadConfigFromFile(
+ path.resolve(__dirname, "../vite.config.ts")
+ );
+
+ return mergeConfig(config, {
+ ...userConfig,
+ // manually specify plugins to avoid conflict
+ plugins: [],
+ });
+ },
};
動作確認
vite.config.ts ファイルが読み込めているか動作確認のために、自作コンポーネントをストーリブックで起動できるか確認してみます。
私は src 直下のファイルを "@"で始まる絶対パスで import できるよう vite.config.ts でエイリアスパスを設定しています。
ストーリーファイルで、自作コンポーネントを"@"で始まる絶対パスで import できればvite.config.ts ファイルが読み込めていると判断できます。
エイリアスパス設定方法はコチラ
Vite+React+TypeScript+EsLintで、Importパスにエイリアスを使うためにハマったこと
まずは src 直下に mycomponent/MyButton.tsx コンポーネントを作成します。
下記のサンプルは MaterialUi を使用していますが、内容はなんでもいいです。
import { Button } from '@mui/material'
export type MyButtonProps = {
text: string
}
export const MyButton = ({ text }: MyButtonProps) => {
return (
<Button variant="contained" size="small" color="warning">
{text}
</Button>
)
}
ストーリーファイルを作成します。
先ほど作成した MyButton コンポーネントを"@"で始まる絶対パスで import します。
import React from 'react'
import { ComponentStory, ComponentMeta } from '@storybook/react'
// "@"で始まる絶対パスで import
import { MyButton } from '@/mycomponent/MyButton'
export default {
title: 'MyComponent/MyButton',
component: MyButton,
argTypes: {
text: {
description: 'ボタンに表示する文言を設定します。'
},
},
} as ComponentMeta<typeof MyButton>
const Template: ComponentStory<typeof MyButton> = (args) => <MyButton {...args} />
export const Default = Template.bind({})
Default.args = {
text: "MyButton",
}
ストーリーブックを実行します。
npm run storybook
表示できました。
以上で、Vite で作成した React アプリケーションに、ストーリブックを導入できました。
まとめ
Storybookは必要だぞ☆
Discussion