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
相关产品推荐
相关产品推荐

