4
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

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

Posted at

はじめに

Bun + Next.js プロジェクトに 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 プロジェクトのルートディレクトリで以下のコマンドを実行

bunx storybook@latest init

この時プロジェクトのルートに /stories ディレクトリが作成されますが、これは使わないので消して大丈夫です。

2. Storybook の設定変更

next.js 用のフレームワークをインストールします。

bun add -D @storybook/nextjs

.storybook/main.ts のフレームワークを変更します。

.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. ストーリーを登録

例として以下のボタンコンポーネントを登録してみます。

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 を作成し以下のようにします。

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 の起動

bun run storybook

Storybook を確認すると、このように表示されました。
bun-next-sb-03.png
定義したプロパティも表示されているので、コンポーネント自体は読み込めているのですが、css が効いていないようです。
Next.js プロジェクトで使用している CSS を適用するために、.storybook/preview.tsglobals.css を読み込みます。

.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

定義したプロパティを画面上で変更できます。color を切り替えてみるとこんな感じ
bun-next-sb-05.gif

おまけ -アクセシビリティテストの追加-

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

Bun でインストールする場合は、以下のコマンドで入りました。

bunx storybook add @storybook/addon-a11y

再度 Storybook を起動するとアクセシビリティテストの項目が増えていて、勝手にテストしてくれました。便利。

グレーのボタン
bun-next-sb-06.png
PASS してました

ブルーのボタン
bun-next-sb-07.png
最低限の色のコントラストを満たしていませんでした

まとめ

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

4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?