React Native Monorepo结构下使用Expo-Router打包成功后运行出现Hermes引擎相关TypeError问题求助
大家好,我目前在Monorepo结构下用React Native + Expo-Router开发应用,遇到了打包成功但App运行报错的棘手问题,想请各位帮忙分析下原因。
问题经过
一开始打包Android时,我碰到了Expo-Router的路径错误:
ERROR node_modules/expo-router/_ctx.android.js:Invalid call at line 2: process.env.EXPO_ROUTER_APP_ROOT First argument of require.context should be a string denoting the directory to require.
按照官方文档指引,我在index.js中添加了根组件注册代码,成功解决了打包问题,Android端终于bundle成功:
import { registerRootComponent } from 'expo'; import { ExpoRoot } from 'expo-router'; export function App() { const ctx = require.context('./app'); return <ExpoRoot context={ctx} />; } try { registerRootComponent(App); } catch (e) { console.error("App registry failed:", e); }
但当我打开App时,出现了一连串Hermes引擎相关的报错:
ERROR ExceptionsManager should be set up after React DevTools to avoid console.error arguments mutation
ERROR TypeError: property is not writable, js engine: hermes
ERROR TypeError: Cannot read property 'default' of undefined, js engine: hermes
ERROR TypeError: property is not writable, js engine: hermes
ERROR TypeError: Cannot read property 'default' of undefined, js engine: hermes
我的配置文件
下面是我当前项目的核心配置,供大家参考:
Babel.config.js
module.exports = function (api) { api.cache(true); process.env.EXPO_ROUTER_APP_ROOT = "./app"; return { presets: ['babel-preset-expo'], plugins: ['expo-router/babel'], }; };
metro.config.cjs
const { getDefaultConfig } = require('@expo/metro-config'); const path = require('path'); const projectRoot = __dirname; const monorepoRoot = path.resolve(projectRoot, '../..'); // 共享的Monorepo包路径 const monorepoPackages = { '@trungthao/domain': path.resolve(monorepoRoot, 'Packages/Domain'), }; // Metro基础配置 const config = getDefaultConfig(projectRoot); // 1. 监听本地与共享包目录 config.watchFolders = [projectRoot, ...Object.values(monorepoPackages)]; // 2. 正确处理软链接 config.resolver.extraNodeModules = new Proxy({}, { get: (_, name) => name in monorepoPackages ? monorepoPackages[name] : path.join(monorepoRoot, 'node_modules', name), }); // 3. 模块解析优先级 config.resolver.nodeModulesPaths = [ path.resolve(projectRoot, 'node_modules'), path.resolve(monorepoRoot, 'node_modules'), ]; // 4. 显式指定入口文件 config.entryFile = 'index.tsx'; module.exports = config;
package.json
{ "name": "mobileapp", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "start": "expo start", "android": "expo run:android", "ios": "expo run:ios", "web": "expo start --web", "build": "expo export", "test": "jest", "eas-build-post-install": "cd ../../Packages/Domain && npm install && npm run build" }, "keywords": [], "author": "", "license": "ISC", "type": "module", "dependencies": { "@expo/metro-config": "^0.20.15", "@expo/vector-icons": "^14.1.0", "@gorhom/bottom-sheet": "^5.1.4", "@ptomasroos/react-native-multi-slider": "^2.2.2", "@react-native-async-storage/async-storage": "2.1.2", "@react-native-community/datetimepicker": "^8.4.1", "@react-navigation/bottom-tabs": "^7.2.0", "@react-navigation/native": "^7.0.14", "@reduxjs/toolkit": "^2.7.0", "@trungthao/domain": "*", "bcryptjs": "^3.0.2", "cors": "^2.8.5", "dotenv": "^16.4.1", "expo": "53.0.13", "expo-blur": "~14.1.5", "expo-constants": "~17.1.6", "expo-dev-client": "~5.2.2", "expo-device": "~7.1.4", "expo-document-picker": "~13.1.6", "expo-file-system": "^18.1.10", "expo-font": "~13.3.1", "expo-haptics": "~14.1.4", "expo-image": "~2.2.1", "expo-image-manipulator": "^13.1.7", "expo-image-picker": "^16.1.4", "expo-linear-gradient": "~14.1.5", "expo-linking": "~7.1.4", "expo-media-library": "^17.1.7", "expo-notifications": "~0.31.3", "expo-router": "~5.1.1", "expo-screen-orientation": "~8.1.7", "expo-splash-screen": "~0.30.9", "expo-status-bar": "~2.2.3", "expo-symbols": "~0.4.5", "expo-system-ui": "~5.0.9", "expo-web-browser": "~13.0.3" } }
我的猜测
目前我怀疑几个方向:
- Monorepo共享包
@trungthao/domain的导出或引用有问题,导致Cannot read property 'default' of undefined - Expo-Router在Monorepo场景下的配置存在遗漏,和Hermes引擎的兼容性问题
index.js中的require.context用法是否和Monorepo的模块解析冲突?
有没有朋友遇到过类似的问题,或者能帮我排查下可能的原因?感谢大家的帮助!
内容来源于stack exchange

