Astroプロジェクトへ試験的にStorybook Astroを導入してみました。
このプロジェクトにはAstroコンポーネントだけでなくReactコンポーネントも含まれており、両方を同じStorybook上でプレビューできる構成を目指しましたが、
導入の過程で複数のエラーに遭遇したので、それぞれの原因と解決方法を記録しておく。
Storybook Astroとは #
Storybook Astroは、Astro向けのコミュニティ製Storybookフレームワークです。
公式サイトによれば、Astroコンポーネントをサーバーサイドでレンダリングしつつ、React、Vue、Svelte、Solid、Preact、Alpine.jsといったUIフレームワークのコンポーネントも同じStorybook上でプレビューできます。
導入前に調べた際の注意点 #
AstroとStorybookの組み合わせを調べた際、同じ「storybook-astro」という名前を持つパッケージが複数見つかった。
今回使用したstorybook-astro/storybook-astro(@storybook-astro/framework)は、Storybook公式ドキュメントのフレームワーク一覧にも掲載されている、コミュニティ支援を受けた本流のプロジェクトである。
同じ名前でも中身がまったく別のパッケージがあるため、npmでインストールする際はパッケージ名がスコープ付きの@storybook-astro/frameworkになっているかを確認する必要がある。
Reactコンポーネントのstoryが表示されない #
Reactコンポーネントのstoryを開くと、Renderer 'astro' not found. Available renderers: reactというエラーが出て描画に失敗した。
原因は@storybook-astro/frameworkの仕様にあった。
このフレームワークは@storybook-astro/renderer/entry-preview.jsの仕様により、プロジェクト全体にparameters.renderer = "astro"をデフォルトで適用する。
Reactコンポーネントのstoryでもこのデフォルト値がそのまま使われてしまい、レンダラーの不一致でエラーになっていた。
対応として、metaにparameters: { renderer: "react" }を明示的に指定が必要で、Astroコンポーネントのstoryにはこの指定は不要のようです。
import type { Meta } from "@storybook/react";
import { Button } from "./Button";
const meta: Meta<typeof Button> = {
title: "app/components/Button",
component: Button,
parameters: {
renderer: "react", // 追加
},
};
export default meta;ボタンは表示されるが装飾がない #
これはAstroに関係ないのですが、エラーは解消されてボタンは表示されたが、Tailwindのスタイルが一切適用されていなかった。
原因は、Tailwindのグローバルスタイル(src/styles/global.css)がStorybookのプレビューに読み込まれていないことだった。
起動ログを確認すると@tailwindcss/viteプラグイン自体は自動で読み込まれていたため、CSSのimportさえ追加すればTailwindは動く状態だった。
対応として、.storybook/preview.tsに下記のようなCSSのimportを追加した。
import "../src/styles/global.css";tags: [“autodocs”]を指定すると型エラーになる #
preview.tsでPreview型を使いtags: ["autodocs"]を含む設定オブジェクトを書いたところ、型エラーが発生した。
原因は、@storybook-astro/frameworkがStorybookのCSF4形式を採用していることだった。
CSF4におけるPreview型は、definePreview()が返す内部オブジェクトの型(_tag、input、composedなどを持つ)であり、tagsを直接持つプレーンな設定オブジェクトの型ではない。
対応として、設定をdefinePreview()関数を通して渡す形に書き換えた。
import { definePreview } from "@storybook-astro/framework";
import "../src/styles/global.css";
export default definePreview({
tags: ["autodocs"],
parameters: {
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/i,
},
},
},
});docsページは出るが、中身が空白 #
main.tsにaddonを追加した結果、Docsページ自体は表示されるようになったが、中身は空白のままだった。
ブラウザで実際にページを開き、コンソールのpageerrorを確認したところ、docsParameter.renderer is not a functionというエラーが出ていた。
原因は、CSF4形式ではmain.tsのaddons配列にパッケージ名を書くだけでは、アドオンのpreview annotationsが読み込まれないことにあった。
生成されるproject-annotations.jsを確認すると、preview.ts側のdefinePreview(...).composedだけが参照されており、main.ts側のaddons設定は反映されていなかった。
その結果、Docsページを描画するparameters.docs.renderer関数自体が存在せず、画面が空白になっていた。
対応として、preview.ts側で@storybook/addon-docsのデフォルトエクスポートをdefinePreview()のaddons配列に明示的に渡した。
import { definePreview } from "@storybook-astro/framework";
import addonDocs from "@storybook/addon-docs"; // 追加
import "../src/styles/global.css";
export default definePreview({
addons: [addonDocs()], // 追加
tags: ["autodocs"],
parameters: {
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/i,
},
},
},
});まとめ #
@storybook-astro/frameworkはCSF4形式を採用しているため、main.tsのaddons配列だけで完結するClassic API方式の設定は一部しか機能しない。- Reactコンポーネントのstoryには
parameters: { renderer: "react" }の明示指定が必須。 - docsアドオンのようなpreview annotationsは
preview.ts側のdefinePreview()にも渡す必要がある。
関連パッケージのバージョン #
@storybook-astro/framework@1.9.0storybook@10.5.4@storybook/builder-vite@10.5.4@storybook/react@10.5.4