添加noHoist后React Native无法解析Monorepo本地模块求助
问题背景
我搭建了基于Yarn Workspaces和Lerna的JS Monorepo项目,结构如下:
/package.json /packages /common (js共享代码) /package.json /mobile (React Native - Metro) /package.json /web (CRA) /package.json
Mobile和Web包在各自的package.json中引入common包:
"dependencies": { "common": "*", }
为避免移动端原生依赖被提升导致构建脚本异常,在根目录package.json中添加noHoist配置:
"workspaces": { "packages": [ "packages/*" ], "nohoist": [ "**/react-native", "**/react-native/**" ] }
Web包在添加noHoist前后均正常运行,但React Native的Metro打包在添加noHoist后失败,报错:
"Error: Unable to resolve module .. could not be found within the project or in these directories: node_modules ../../node_modules"
common包确实存在于根目录node_modules中,尝试手动链接问题依旧,且未将common加入noHoist。当前Metro配置如下:
const path= require('path'); const watchFolders = [ path.resolve(`${__dirname}`), // Relative path to package node_modules path.resolve(`${__dirname}/../../node_modules`), // Relative path to root node_modules ]; module.exports = { transformer: { getTransformOptions: async () => ({ transform: { experimentalImportSupport: false, inlineRequires: true, }, }),}, maxWorkers: 2, watchFolders, };
解决思路
修正Metro的watchFolders与解析配置
当前的watchFolders配置未明确指向common包的位置,且缺少模块解析路径的配置。调整Metro配置,让它能扫描到根目录的node_modules和common包:const path = require('path'); const rootDir = path.resolve(__dirname, '../../'); const watchFolders = [ rootDir, // 扫描根目录下所有packages和node_modules path.resolve(rootDir, 'packages/common'), // 明确指定common包路径 path.resolve(rootDir, 'node_modules'), ]; module.exports = { transformer: { getTransformOptions: async () => ({ transform: { experimentalImportSupport: false, inlineRequires: true, }, }), }, maxWorkers: 2, watchFolders, resolver: { nodeModulesPaths: [ path.resolve(__dirname, 'node_modules'), // 本地包的node_modules path.resolve(rootDir, 'node_modules'), // 根目录的node_modules ], }, };检查common包的入口配置
确保common包的package.json中存在正确的main字段,指向你的代码入口文件,例如:{ "name": "common", "main": "index.js", // 或src/index.js,根据实际结构调整 "version": "1.0.0" }缺失
main字段会导致Metro无法找到模块的入口。优化noHoist规则的精准度
全局的**/react-native规则可能影响模块解析的路径逻辑,改为只针对mobile包下的react-native:"workspaces": { "packages": ["packages/*"], "nohoist": [ "mobile/react-native", "mobile/react-native/**" ] }这种精准规则只会限制mobile包内的react-native不被提升,避免干扰其他模块的解析。
清理缓存并重新安装依赖
缓存问题可能导致模块解析异常,执行以下步骤:- 清理Yarn缓存:
yarn cache clean - 删除所有node_modules(根目录及各packages下的)
- 重新安装依赖:
yarn install - 重置Metro缓存:
npx react-native start --reset-cache
- 清理Yarn缓存:
验证Lerna与Yarn Workspaces的兼容性
如果使用Lerna,确保lerna.json中开启了useWorkspaces,让Lerna复用Yarn的工作区配置:{ "packages": ["packages/*"], "version": "independent", // 或你使用的版本策略 "useWorkspaces": true }避免Lerna和Yarn Workspaces的配置冲突导致模块路径异常。
内容的提问来源于stack exchange,提问作者Nabeel Zanabeet

