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

Nx单体仓库中React Native调用共享库遇Metro无法解析fs错误

Nx单体仓库中React Native调用含Next.js依赖的共享库时Metro报“Cannot resolve fs”错误

我用Nx搭建了包含Next.js和React Native的单体仓库,里面有个shared-lib共享库。Web端调用共享库的内容(比如SVG、函数)一切正常,但React Native端调用时Metro打包工具报错,具体是Cannot resolve fs。

排查后发现问题根源:如果共享库中的组件(比如共享Provider或Hook)引入了Next.js的依赖,比如:

import { useRouter } from 'next/router';
const { locale } = useRouter();

并且把这些内容导出到shared-lib的index.ts后,React Native就无法正常运行,触发上述错误。


具体报错信息

报错信息1

BUNDLE  src/main.tsx

error: Error: Cannot resolve fs
    at /Users/mac/projects/nx-app/node_modules/@nx/react-native/plugins/metro-resolver.js:33:15
    at Object.resolve (/Users/mac/projects/nx-app/node_modules/metro-resolver/src/resolve.js:32:12)
    at ModuleResolver.resolveDependency (/Users/mac/projects/nx-app/node_modules/metro/src/node-haste/DependencyGraph/ModuleResolution.js:73:31)
    at DependencyGraph.resolveDependency (/Users/mac/projects/nx-app/node_modules/metro/src/node-haste/DependencyGraph.js:231:43)
    at /Users/mac/projects/nx-app/node_modules/metro/src/lib/transformHelpers.js:156:21
    at resolveDependencies (/Users/mac/projects/nx-app/node_modules/metro/src/DeltaBundler/buildSubgraph.js:42:25)
    at visit (/Users/mac/projects/nx-app/node_modules/metro/src/DeltaBundler/buildSubgraph.js:83:30)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async Promise.all (index 2)
    at async visit (/Users/mac/projects/nx-app/node_modules/metro/src/DeltaBundler/buildSubgraph.js:92:5)

报错信息2

(NOBRIDGE) ERROR  [Error: InternalError Metro has encountered an error: Cannot resolve fs: /Users/mac/projects/nx-app/node_modules/@nx/react-native/plugins/metro-resolver.js (33:15)

  31 |             console.log(chalk.red(`[Nx] Unable to resolve with any resolver: ${realModuleName}`));
  32 |         }
> 33 |         throw new Error(`Cannot resolve ${chalk.bold(realModuleName)}`);
     |               ^
  34 |     };
  35 | }
  36 | exports.getResolveRequest = getResolveRequest;]

当前配置

Metro配置

const { withNxMetro } = require('@nx/react-native');
const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config');
const path = require('path');
const defaultConfig = getDefaultConfig(__dirname);
const { assetExts, sourceExts } = defaultConfig.resolver;

/**
 * Metro configuration
 * https://reactnative.dev/docs/metro
 *
 * @type {import('metro-config').MetroConfig}
 */
const customConfig = {
  transformer: {
    babelTransformerPath: require.resolve('react-native-svg-transformer'),
  },
  resolver: {
    assetExts: assetExts.filter((ext) => ext !== 'svg'),
    sourceExts: [...sourceExts, 'cjs', 'mjs', 'svg'],
  },
  watchFolders: [path.resolve(__dirname, '../../node_modules')],
};

module.exports = withNxMetro(mergeConfig(defaultConfig, customConfig), {
  // Change this to true to see debugging info.
  // Useful if you have issues resolving modules
  debug: false,
  // all the file extensions used for imports other than 'ts', 'tsx', 'js', 'jsx', 'json'
  extensions: [],
  // Specify folders to watch, in addition to Nx defaults (workspace libraries and node_modules)
  watchFolders: [],
});

Webpack配置

const { composePlugins, withNx } = require('@nx/webpack');
const { withReact } = require('@nx/react');

// Nx plugins for Webpack.
module.exports = composePlugins(
  withNx(),
  withReact({
    // Uncomment this line if you don't want to use SVGR
    // See: https://react-svgr.com/
    // svgr: false
  }),
  (config) => {
    // Update the Webpack configuration as needed here.
    // e.g. `config.plugins.push(new MyPlugin())`

    config.resolve.alias = {
      ...(config.resolve.alias ?? {}),
      // 'react-native$': 'react-native-web',
    };
    config.resolve.extensions = [
      '.web.tsx',
      '.web.ts',
      '.web.jsx',
      '.web.js',
      ...config.resolve.extensions,
    ];
    config.module.rules.push({
      test: /\.(js|jsx)$/,
      include: /react-native-vector-icons/,
      loader: 'babel-loader',
      options: {
        presets: [
          '@babel/preset-env',
          ['@babel/preset-react', { runtime: 'automatic' }],
        ],
      },
    });

    return config;
  },
);

解决方法

1. 拆分共享库中的平台相关代码

把依赖Next.js的代码和通用代码彻底分离,避免共享库入口导出平台专属内容:

  • 在shared-lib中新建web目录,存放依赖Next.js的组件/Hook(比如用到useRouter的代码)
  • 通用代码保留在根目录,供两端调用
  • 共享库的index.ts只导出通用内容,Web端单独从shared-lib/web导入平台专属代码

2. 配置Metro忽略Next.js依赖

修改Metro配置,让它在打包React Native时直接忽略Next.js相关模块:
在customConfig的resolver中添加blockList:

resolver: {
  assetExts: assetExts.filter((ext) => ext !== 'svg'),
  sourceExts: [...sourceExts, 'cjs', 'mjs', 'svg'],
  blockList: [/next\/.*/], // 忽略所有next模块
},

3. 使用条件导入区分平台

如果必须在共享库中保留平台相关代码,用条件判断或动态导入隔离Web端依赖:

let locale = 'en';
// 仅在Web环境加载Next.js依赖
if (typeof window !== 'undefined') {
  const { useRouter } = require('next/router');
  locale = useRouter().locale;
}

或者用React Native的Platform API:

import { Platform } from 'react-native';

if (Platform.OS === 'web') {
  const { useRouter } = require('next/router');
  // 处理Web端逻辑
}

4. 检查Nx库类型配置

确保shared-lib的project.json中,targets.build.options.outputPath和构建器配置正确,避免将Web端依赖打包进通用输出。同时,不要把Next.js依赖添加到共享库package.json的dependencies中,而是放在peerDependencies,让Web端项目自行安装。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 06:42:34