Rork で AI に新しい画面を作ってもらって npx expo start を叩いた瞬間、赤い画面でこう出ることがあります。
Unable to resolve module
xxxfrom/path/to/file.tsx
最初に見るとどこから手を付けていいか分かりづらいエラーですが、原因のパターンはほぼ決まっています。私自身、Rork で生成したコードを動かしていてこのエラーに何度もぶつかりましたが、確認する順番さえ覚えてしまえば数分で解決できるようになります。今日はその確認順序を整理して共有します。
このエラーが出る仕組み
React Native の開発サーバー(Metro バンドラー)は、import 文を1つずつたどってアプリの依存ツリーを組み立てます。その途中でファイルやパッケージが見つからないと、Metro はそこで処理を止めて「Unable to resolve module」を返します。
ここで重要なのは、Metro は npm パッケージとローカルファイルの両方をこのエラーで報告するという点です。たとえば import { Camera } from "expo-camera" でも import { Header } from "../components/Header" でも、解決できなければ同じメッセージが出ます。原因の切り分けはエラーメッセージの後半部分に書かれた「from」のあとのファイルパスを見て判断します。
1. パッケージがインストールされていない
頻度として最も多いのがこれです。Rork の AI が生成したコードに、まだ手元の package.json に入っていないパッケージが含まれているケースです。
# エラー例
Unable to resolve module react-native-reanimated from src/screens/Home.tsx# 解決
npx expo install react-native-reanimatedポイントは、純粋な npm install ではなく npx expo install を使うことです。Expo SDK のバージョンに合った互換性のある版を自動で選んでくれるため、後段のビルドエラーを未然に防げます。Rork の生成コードで使われがちな expo-image、expo-blur、react-native-svg などは、これで一発です。
2. Metro のキャッシュが壊れている
package.json には載っていてインストール済みなのにエラーが消えない場合、Metro のキャッシュが古いままという可能性が高いです。新しいパッケージを追加した直後や、ブランチを切り替えた直後によく発生します。
# キャッシュをクリアして起動
npx expo start -c
# それでも直らないとき(深いキャッシュも消す)
rm -rf node_modules/.cache
watchman watch-del-all
npx expo start -c-c フラグは Metro の trans former / haste map キャッシュをまとめてリセットします。Rork で AI が生成したコードを大きく書き換えたあとは、習慣的にこれを使うとトラブルが減ります。
3. import パスのタイポ・大文字小文字の食い違い
開発機(macOS のデフォルトファイルシステム)は大文字小文字を区別しないことが多いのですが、ビルド環境(Linux ベースのクラウドビルド・iOS シミュレータの一部キャッシュ)では区別されます。手元では動いて EAS Build や本番アプリで失敗するケースは、ほぼこれです。
// ❌ ファイル名は Header.tsx なのに小文字でインポート
import { Header } from "./components/header";
// ✅ ファイル名と完全一致
import { Header } from "./components/Header";拡張子のうっかりミスもあります。./utils/format でディレクトリの index.ts を読んでいるつもりが、実は format.ts というファイルだった、というパターンです。エラーメッセージの「from」のあとのパスを起点に、エディタの補完で開き直すと一瞬で気づけます。
4. パスエイリアスを babel.config.js か metro.config.js に書き忘れている
tsconfig.json に "paths" を設定して @/components/Button のような書き方を使うと、TypeScript のエラーは消えても Metro が解決できないことがあります。これは TypeScript と Metro が別の仕組みでパスを解決しているためで、両方に設定する必要があります。
// babel.config.js
module.exports = function (api) {
api.cache(true);
return {
presets: ["babel-preset-expo"],
plugins: [
[
"module-resolver",
{
root: ["./"],
alias: {
"@": "./src",
},
},
],
],
};
};babel-plugin-module-resolver を入れたあとは Metro キャッシュのクリア(前述の -c フラグ)も忘れずに行ってください。プラグインを足しただけではキャッシュが古いまま参照されてエラーが消えないことが多いです。
5. 開発ビルドが必要なネイティブモジュールを Expo Go で動かしている
react-native-vision-camera や react-native-mmkv のような、ネイティブモジュールを必要とするライブラリは Expo Go では動きません。Expo Go は Expo SDK が用意している標準モジュールしかバンドルしていないため、Metro が解決しようとして失敗します。
この場合は Development Build に切り替える必要があります。
# 開発ビルドを作成
npx expo prebuild --clean
npx expo run:ios # または run:androidRork の AI に「ネイティブモジュールを使わない方針で」と伝えてコードを再生成し直すという選択肢もあります。プロトタイプ段階では Expo Go のままで進めて、機能要件が固まったタイミングで Development Build に切り替えるのが、私としては実用的だと思っています。
確認順序のまとめ
エラーが出たら、上から順にチェックすると最短で原因にたどり着けます。
- パッケージは
package.jsonに入っているか → なければnpx expo install - Metro キャッシュは新鮮か →
npx expo start -c - import パスは正しいか(大文字小文字・拡張子・存在)
- パスエイリアス(
@/)を使っているなら Babel 側にも設定があるか - ネイティブモジュールなら Development Build に切り替えているか
このフローを身につけておくと、Rork の生成コードに依存パッケージが追加されても落ち着いて対処できるようになります。Metro 周りのエラーをもっと体系的に押さえたい方は、Rork で Metro バンドラーや Fast Refresh が動かないときのトラブルシューティング と Rork 生成コードのランタイムエラーを直す方法 もあわせて読むと、ビルド時・実行時両面の知識がつながります。
React Native / Expo の Metro の挙動を腰を据えて
次にこのエラーが出たときは、まず npx expo install と npx expo start -c の2つを試してみてください。経験上、これだけで7〜8割のケースは解決します。