You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

添加noHoist后React Native无法解析Monorepo本地模块求助

Yarn Workspaces + Lerna Monorepo中React Native Metro打包失败的解决思路

问题背景

我搭建了基于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不被提升,避免干扰其他模块的解析。

  • 清理缓存并重新安装依赖
    缓存问题可能导致模块解析异常,执行以下步骤:

    1. 清理Yarn缓存:yarn cache clean
    2. 删除所有node_modules(根目录及各packages下的)
    3. 重新安装依赖:yarn install
    4. 重置Metro缓存:npx react-native start --reset-cache
  • 验证Lerna与Yarn Workspaces的兼容性
    如果使用Lerna,确保lerna.json中开启了useWorkspaces,让Lerna复用Yarn的工作区配置:

    {
      "packages": ["packages/*"],
      "version": "independent", // 或你使用的版本策略
      "useWorkspaces": true
    }
    

    避免Lerna和Yarn Workspaces的配置冲突导致模块路径异常。

内容的提问来源于stack exchange,提问作者Nabeel Zanabeet

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 20:31:34