【備忘録】Bun + Next.js プロジェクトに Storybook を導入する

# はじめに
**Bun + Next.js** プロジェクトに **Storybook** を導入しようとしたところ、あまり情報が載っていなかったので、備忘録も兼ねてまとめます。

- [前提](#前提)
- [実行手順](#実行手順)
    1. [storybook のインストール](#1-storybook-のインストール)
    2. [storybook の設定変更](#2-storybook-の設定変更)
    3. [ストーリーを登録](#3-ストーリーを登録)
    4. [storybook の起動](#4-storybook-の起動)
- [おまけ -アクセシビリティテストの追加-](#おまけ--アクセシビリティテストの追加-)
- [まとめ](#まとめ)

# 環境
- **Next.js**: v15.3.0
- **bun**: v1.2.8
- **Storybook**: v8.6.12
- **Tailwind CSS**: ≥ v4

# 前提
- 既に Bun で構築済みの Next.js のプロジェクトに Storybook を導入する
- Tailwind CSS を使用している

# 実行手順

## 1. Storybook のインストール
Next.js プロジェクトのルートディレクトリで以下のコマンドを実行
```bash
bunx storybook@latest init
```
この時プロジェクトのルートに `/stories` ディレクトリが作成されますが、これは使わないので消して大丈夫です。

## 2. Storybook の設定変更
next.js 用のフレームワークをインストールします。
```bash
bun add -D @storybook/nextjs
```
`.storybook/main.ts` のフレームワークを変更します。
```diff:.storybook/main.ts
- import type { StorybookConfig } from "@storybook/experimental-nextjs-vite";
+ import type { StorybookConfig } from "@storybook/nextjs";

const config: StorybookConfig = {
  stories: ["../src/**/*.mdx", "../src/**/*.stories.@(js|jsx|mjs|ts|tsx)"],
  addons: [
    "@storybook/addon-essentials",
    "@storybook/addon-onboarding",
    "@chromatic-com/storybook",
    "@storybook/experimental-addon-test",
  ],
  framework: {
-   name: "@storybook/experimental-nextjs-vite",
+   name: "@storybook/nextjs",
    options: {},
  },
  staticDirs: ["../public"],
};
export default config;
```

## 3. ストーリーを登録
例として以下のボタンコンポーネントを登録してみます。
```ts:src/components/ui/Button.tsx
import React from "react";

interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
  color?: "gray" | "blue" | "red" | "green";
  className?: string;
}

export default function Button({ color, className, ...props }: ButtonProps) {
  const baseClass = "rounded-md px-6 py-3 text-white";
  const colorClass =
    color === "gray"
      ? "bg-zinc-500 hover:bg-zinc-600"
      : color === "blue"
      ? "bg-sky-600 hover:bg-sky-700"
      : color === "red"
      ? "bg-red-600 hover:bg-red-700"
      : color === "green"
      ? "bg-green-600 hover:bg-green-700"
      : "";

  return (
    <button
      className={baseClass + " " + colorClass + " " + className}
      {...props}
    />
  );
}
```
`Button.stories.tsx` を作成し以下のようにします。
```ts:src/components/ui/stories/Button.stories.tsx
import { Button } from "@/components/ui/Button";
import type { Meta, StoryObj } from "@storybook/react";

const meta: Meta<typeof Button> = {
  title: "UI/Button",
  component: Button,
};
export default meta;

type Story = StoryObj<typeof Button>;

export const Default: Story = {
  args: {
    color: "gray",
    children: "ボタン",
  },
};
```

## 4. Storybook の起動
```bash
bun run storybook
```

Storybook を確認すると、このように表示されました。
![bun-next-sb-03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529398/ec332c3c-7e4a-47e5-a18b-2057147c1323.png)
定義したプロパティも表示されているので、コンポーネント自体は読み込めているのですが、css が効いていないようです。
Next.js プロジェクトで使用している CSS を適用するために、`.storybook/preview.ts` で `globals.css` を読み込みます。
```diff:.storybook/preview.ts
import type { Preview } from "@storybook/react";
+ import "../src/app/globals.css";

const preview: Preview = {
  parameters: {
    controls: {
      matchers: {
        color: /(background|color)$/i,
        date: /Date$/i,
      },
    },
  },
};

export default preview;
```
無事、CSS が効きました。
![bun-next-sb-04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529398/77a33cf9-f79f-4b3d-b5c7-ab2771963495.png)

定義したプロパティを画面上で変更できます。`color` を切り替えてみるとこんな感じ
![bun-next-sb-05.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529398/c8145a02-1666-4b15-81f8-34626c233c9e.gif)

# おまけ -アクセシビリティテストの追加-
アクセシビリティテストも追加したかったため、Bun を使った追加方法も紹介しておきます。

https://storybook.js.org/docs/writing-tests/accessibility-testing

Bun でインストールする場合は、以下のコマンドで入りました。
```bash
bunx storybook add @storybook/addon-a11y
```
再度 Storybook を起動するとアクセシビリティテストの項目が増えていて、勝手にテストしてくれました。便利。

**グレーのボタン**
![bun-next-sb-06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529398/4e1c0b42-7232-45d3-b5c5-fdf8c2756018.png)
PASS してました

**ブルーのボタン**
![bun-next-sb-07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529398/9ebf906d-41d5-4c9d-933b-cc3646b60a8a.png)
最低限の**色のコントラスト**を満たしていませんでした

# まとめ
Bun を使った Storybook の導入はまだ情報が少なく、あってもStorybookをインストールするところまでのものが多い印象なので、自分が躓いた部分の備忘録も兼ねて記事にしました。
特に PostCSS 周りの設定や Next.js プロジェクトの CSS の適用など、細かいハマりポイントがいくつかあったので、今回の記事では自分が実際に遭遇したエラーやその解決方法を中心にまとめました。
同じように Bun × Next.js プロジェクトへ Storybook を導入したい方や、同じエラーに遭遇した方の参考になれば幸いです！