@storybook/experimental-nextjs-vite で SVGR を使うには
結論
前提:Next.js のセットアップと SVGRのドキュメントにあるNext.js用の設定をしている
1. vite-plugin-svgr をインストール
2. .storybook/main.tsに以下のように記述
code:main.ts
import svgr from "vite-plugin-svgr";
const config: StorybookConfig = {
// ...省略...
viteFinal: (config) => {
// add svgr support
config.plugins = [
...config.plugins!,
svgr({
include: /\.svg$/,
}),
];
// HACK: To handle *.svg (without ?url) imports, we need to modify the existing plugin: "vite-plugin-storybook-nextjs-image"
// (set by @storybook/experimental-nextjs-vite)
// Because this plugin doesn't have a option to exclude certain file types
// TODO: Remove this workaround when the way to exclude certain file types is supported by the plugin
config.plugins = config.plugins!.flat().map((plugin) => {
if (
typeof plugin === "object" &&
plugin !== null &&
"name" in plugin &&
plugin.name === "vite-plugin-storybook-nextjs-image"
) {
return {
...plugin,
// The plugin handles *.svg by resolveId hook
// see https://github.com/storybookjs/vite-plugin-storybook-nextjs/blob/b0e2b83ed5cfe666388a87a1935c9b511788eb16/src/plugins/next-image/plugin.ts#L54
resolveId(id, importer) {
// Skip .svg imports
if (id.endsWith(".svg")) {
return null;
}
// @ts-expect-error resolveId hook of vite-plugin-storybook-nextjs-image is a function
return plugin.resolveId(id, importer);
},
};
}
return plugin;
});
// ...省略...
return config;
},
};
export default config;
動いている例は /icons/GitHub.icon ygkn/storybook-nextjs-vite-svgr へ
これは何?
前提知識
@storybook/experimental-nextjs-vite は Next.js プロジェクトの Storybook を Vite を使って動かすことができるやーつ
これにより、Vitest でInteraction Testを実行できたり、起動が早くなったり、いろいろ Happy になれる
それまでは Webpack で動かしていた(= @storybook/nextjs)
詳細は Storybook 8.3 で導入された Vitest 対応を React と Next.js で試す などをどうぞ
SVGR は、SVG ファイルを React コンポーネントとしてインポートできるやーつ
code:tsx
import SvgImage from "./image.svg"
<SvgImage />
SVGRは Next.js 用の設定手順を示している → Next.js - SVGR
これは、以下のことをするもの
1. デフォルトの *.svg と、その他画像ファイルをハンドルする loader から *.svg を除外する
2. ↑のloader の設定を複製して、*.svg?url でSVGファイルを読み込めるようにする
3. SVGR loader を追加する
なので、SVGR が示している Webpack の設定と同じことを、Viteの設定でする
Webpack の設定 rules には、loaderから特定のファイルの種類を除外する設定(exclude → Rule.exclude)があるが、Vite には同様のものが無い
無いよね…? もし ygkn.icon が知らないだけならお知らせください
なので、画像を読み込んでいるVite plugin("vite-plugin-storybook-nextjs-image")の処理(=ここではresolveIdフック)に横入りして(!)インポート文のクエリ(?...)が無い*.svg(=id.endsWith(".svg")) の場合は無視(=return null)して、SVGR のプラグインに処理を引き渡すようにする
つらい
†experimental† という感じがする
理想的には?
@storybook/experimental-nextjs-vite とかに SVGR と共存できる何かしらのオプションがほしいな〜〜
いちおう、TODO コメントにオプションができたらハック箇所を消すように書いてあげるとあとから見る人(∋自分)に親切
でもWebpackのSVGRもあとからごちゃごちゃしてるし、きついかな〜
Viteのpluginにexlcude設定ができるのでもおk