🤖
expo-routerを使ってるreact-nativeにstorybookを入れる
はじめに
expo-routerに癖があり(?)少し詰まったのでメモ程度に記録を残します。
プロジェクト作成
$ npx create-expo-app@latest
Creating an Expo project using the default template.
To choose from all available templates pass in the --template arg:
$ npx create-expo-app --template
To choose from all available examples pass in the --example arg:
$ npx create-expo-app --example
√ What is your app named? ... expo-router-storybook
√ Downloaded and extracted project files.
Storybookの初期化
$ npx storybook@latest init
╭──────────────────────────────────────────────────────╮
│ │
│ Adding Storybook version 8.5.8 to your project.. │
│ │
╰──────────────────────────────────────────────────────╯
• Detecting project type. ✓
Installing dependencies...
react-nativeの設定
storybookを初期化するとシェルに次のログが表示されます。
1. Replace the contents of your app entry with the following
export {default} from './.storybook';
2. Wrap your metro config with the withStorybook enhancer function like this:
const withStorybook = require('@storybook/react-native/metro/withStorybook');
module.exports = withStorybook(defaultConfig);
1をどうやるかわからないので先に2を解決します。
metroのconfigを編集可能にするために次のコマンドを実行します
$ npx expo customize metro.config.js
Generating: metro.config.js
2に書かれてる指示に従う
metro.config.js
// Learn more https://docs.expo.io/guides/customizing-metro
const { getDefaultConfig } = require('expo/metro-config');
const withStorybook = require('@storybook/react-native/metro/withStorybook');
/** @type {import('expo/metro-config').MetroConfig} */
const config = getDefaultConfig(__dirname);
module.exports = withStorybook(config);
エントリーポイントの修正
1に書かれてる指示に従いたいのですが、エントリーポイントはどうやらpackage.jsonのmainフィールドに定義されてるファイルがそうらしいです(https://zenn.dev/lemonadern/scraps/4907be3187186c)
なのでエントリーポイント用ファイルを作って元のエントリーポイントと置き換えます。
package.json
{
...
- "main": "expo-router/entry",
+ "main": "./entry.ts",
...
}
entry.ts
// コピペ元: https://github.com/expo/expo/blob/main/packages/expo-router/entry.js
// This is aliased to another location when server components are enabled.
// We use this intermediate file to avoid issues with aliases not applying to package.json main field resolution.
import 'expo-router/entry-classic';
これでエントリーポイントに修正が効くようになりました。
続けて1の指示に従います。(ちょっと工夫してます)
entry.ts
// ↓を変数で管理してますが、環境変数にするなどお好きな方法で管理してください。
const isStorybook = false;
if (isStorybook){
// storbookを表示するための処理
const {registerRootComponent} = require("expo");
const Storybook = require("./.storybook").default;
registerRootComponent(Storybook);
}else{
// 参考: https://github.com/expo/expo/blob/main/packages/expo-router/entry.js
require("expo-router/entry-classic");
}
できました。
Discussion