Android release构建崩溃:Yarn Workspaces monorepo无法找到共享模块
问题背景
- 基于Yarn Workspaces搭建monorepo仓库,包含两个核心目录:
- mobile:存放React Native项目
- common:存放跨项目复用的公共代码,mobile项目直接依赖该目录下的代码
- 故障表现:安卓debug模式可正常运行,切换为release模式后启动立刻崩溃,报错日志如下:
E/ReactNativeJS: Invariant Violation: Module AppRegistry is not a registered callable module (calling runApplication). A frequent cause of the error is that the application entry file path is incorrect. This can also happen when the JS bundle is corrupt or there is an early initialization error when loading React Native. --------- beginning of crash 2022-06-07 23:48:09.865 5772-5799/? E/AndroidRuntime: FATAL EXCEPTION: mqt_native_modules Process: com.myapp.mobile, PID: 5772 com.facebook.react.common.JavascriptException: TypeError: t is not a function. (In 't(u)', 't' is undefined), stack: <unknown>@460:2846 map@-1 <unknown>@460:2825 N@457:7733 <unknown>@455:172 h@2:1585 <unknown>@453:262 h@2:1585 <unknown>@403:148 h@2:1585 <unknown>@6:57 h@2:1585 d@2:958 global code@529:3 at com.facebook.react.modules.core.ExceptionsManagerModule.reportException(ExceptionsManagerModule.java:72) at java.lang.reflect.Method.invoke(Native Method) at com.facebook.react.bridge.JavaMethodWrapper.invoke(JavaMethodWrapper.java:372) at com.facebook.react.bridge.JavaModuleWrapper.invoke(JavaModuleWrapper.java:188) at com.facebook.react.bridge.queue.NativeRunnable.run(Native Method) at android.os.Handler.handleCallback(Handler.java:938) at android.os.Handler.dispatchMessage(Handler.java:99) at com.facebook.react.bridge.queue.MessageQueueThreadHandler.dispatchMessage(MessageQueueThreadHandler.java:27) at android.os.Looper.loop(Looper.java:223) at com.facebook.react.bridge.queue.MessageQueueThreadImpl$4.run(MessageQueueThreadImpl.java:228) at java.lang.Thread.run(Thread.java:923)
- 初步排查结果:已定位报错由common模块导入的函数引发,确认common模块存在于
node_modules目录,但无法确认是否被正确打包进JS bundle。 - mobile目录下package.json配置参考:

排查修复方案
这是Yarn Workspaces搭配React Native搭建monorepo的典型配置问题,debug模式正常、release模式崩溃的核心原因是:Metro打包器默认不会转译node_modules目录下的代码,而Yarn Workspaces是通过软链接形式把common目录映射到mobile项目的node_modules下,common内的源码未经过Babel转译就进入release打包流程,叠加release模式的代码压缩混淆逻辑,就会出现函数未定义的报错,最终连锁触发AppRegistry注册失败的崩溃。
按以下步骤逐一配置修复即可:
- 调整Metro配置,正确识别monorepo目录结构
在mobile项目根目录修改metro.config.js,把common目录、monorepo根目录的依赖目录加入Metro的监听和查找范围,避免识别不到软链的工作区包:const path = require('path'); const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config'); const config = { watchFolders: [ // 指向common模块的绝对路径,按实际目录层级调整 path.resolve(__dirname, '../common'), ], resolver: { nodeModulesPaths: [ path.resolve(__dirname, 'node_modules'), // 指向monorepo根目录的node_modules,处理依赖提升场景 path.resolve(__dirname, '../node_modules'), ], }, }; module.exports = mergeConfig(getDefaultConfig(__dirname), config); - 调整Babel配置,转译common模块源码
修改mobile项目下的babel.config.js,把common目录加入Babel转译范围,避免未经过语法转换的代码进入release包:module.exports = { presets: ['module:metro-react-native-babel-preset'], include: [ 'src', // 匹配common目录下所有源码文件,按实际目录层级调整 '../common/**', ], }; - 全量清理缓存后重新打包验证
Metro和Babel的缓存优先级很高,配置修改后必须彻底清理缓存,否则旧的异常打包产物会持续干扰结果:cd mobile # 清理安卓构建缓存 rm -rf android/app/build # 启动Metro时重置缓存 yarn start --reset-cache # 重新打release安装包测试 yarn android --variant=release - 异常兜底校验
如果完成以上配置后仍存在问题,逐一检查以下点:- 检查common模块下
package.json的main字段是否指向正确的入口文件,避免导入路径解析到空值 - 检查common模块引用的第三方依赖是否都能被Metro正确解析,部分被提升到monorepo根目录的依赖如果识别失败,可以在mobile目录下重新安装对应依赖,或者在Metro配置中额外添加依赖查找路径
- 可以单独执行bundle打包命令生成未压缩的release bundle,直接搜索common模块的特征代码确认是否被正确打包,同时检查bundle内是否存在语法异常:
npx react-native bundle --platform android --dev false --entry-file index.js --bundle-output ./test-release.bundle --assets-dest ./test-assets
- 检查common模块下
内容的提问来源于stack exchange,提问作者Joshua
相关产品推荐
相关产品推荐

