🥺
Next.jsのサブパスからStorybookを公開する
Next.jsのサブパスからStorybookを公開する際につまづいたポイントが何点かあったので、メモとして残しておく。
(ZennのStorybook公開してくれないかな・・・)
動作環境
Next.js 11.1.2
Storybook 6.3.10
Storybookからアセットを参照出来るようにする
サブパスで公開するとアセットのリンク切れが発生するので、ビルド時にリンクのプレフィックスを指定出来るようにする。
./storybook/main.js
const { merge } = require('webpack-merge');
const prefix = process.env.STORYBOOK_PREFIX ? `/${process.env.STORYBOOK_PREFIX}` : '';
module.exports = {
...
managerHead: (head) => {
return `
${head}
<link rel="shortcut icon" type="image/x-icon" href="${prefix}/favicon.ico">
<script>
window['PREVIEW_URL'] = '${prefix}/iframe.html';
</script>
`;
},
webpackFinal: async (config) => {
return merge(config, {
output: {
publicPath: `${prefix}/`,
},
});
},
managerWebpack: async (config) => {
return merge(config, {
output: {
publicPath: `${prefix}/`,
},
});
},
};
Storybookのビルドスクリプトを書き換える
ビルド時にSTORYBOOK_PREFIX
へ任意の値を指定し、ビルド出力先をNext.jsのpublicフォルダ配下へと変更する。
"scripts": {
- "build:storybook": "build-storybook",
+ "build:storybook": "STORYBOOK_PREFIX=storybook build-storybook -o ./public/storybook",
},
Next.jsのrewritesを設定する
このままだとindex.html
まで入力しないと表示出来ないので、rewritesで参照先を変更する。
next.config.js
module.exports = {
...
rewrites: async () => {
return [
{
source: '/storybook',
destination: '/storybook/index.html',
},
];
},
};
Next.jsのImageコンポーネントのモックを定義する
Next.jsのImageコンポーネントを使用しているとStorybookでエラーが発生する為、imgタグと置き換えるようなモックを定義する必要がある。
.storybook/preview.js
import * as Image from 'next/image';
Object.defineProperty(Image, 'default', {
configurable: true,
value: props => <img {...props} />
});
TypeScriptの絶対インポートをStorybookに認識させる
TypeScriptで絶対インポートを使用しているとStorybookでモジュール解決が出来なくなってしまうので、webpackFinalに別途設定する必要がある。
./storybook/main.js
const path = require('path');
const { merge } = require('webpack-merge');
const getBaseDir = () => {
const tsconfig = require('../tsconfig.json');
return path.resolve(process.cwd(), tsconfig.compilerOptions.baseUrl);
};
module.exports = {
...
webpackFinal: async (config) => {
return merge(config, {
resolve: {
modules: [getBaseDir()],
},
});
},
};
Discussion