🤖

expo-routerを使ってるreact-nativeにstorybookを入れる

2025/02/22に公開

はじめに

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