Metro

Metro 模块联邦(Module Federation)为 React Native 移动开发带来了分布式架构的能力。

概述

React Native 的模块联邦实现使用了自定义的 Metro 打包器集成,能够实现:

  • 微前端架构 —— 在 React Native 应用中实现微前端
  • 代码共享 —— 在多个 React Native 应用之间共享代码
  • 独立部署 —— 各个应用模块可以独立部署
  • 运行时模块加载 —— 支持动态更新

注意:Metro 打包器的模块联邦支持仍处于实验阶段,可能缺少部分功能或集成。依赖自定义 Metro 配置的项目或库目前尚不支持,可能无法正常工作。

React Native 模块联邦生态系统由以下几个包组成:

  • @module-federation/metro - 与 Metro 的核心集成,用于启用模块联邦
  • @module-federation/metro-plugin-rnc-cli - React Native CLI 集成
  • @module-federation/metro-plugin-rnef - React Native Enterprise Framework 集成

安装

在 React Native 项目中安装所需的包(使用你喜欢的包管理器):

# 核心包(必需) pnpm add @module-federation/metro  # 如果项目使用 React Native CLI pnpm add @module-federation/metro-plugin-rnc-cli  # 如果项目使用 React Native Enterprise Framework (RNEF) pnpm add @module-federation/metro-plugin-rnef

配置

使用 withModuleFederation 包装你的 Metro 配置以启用模块联邦。
你需要在所有联邦模块(宿主应用和子应用)的 Metro 配置中使用该方法。

const { withModuleFederation } = require('@module-federation/metro'); const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config');  const config = {};  module.exports = withModuleFederation(  mergeConfig(getDefaultConfig(__dirname), config),  {  // 模块联邦配置遵循官方文档格式:  // https://module-federation.io/configure/index.html  // 注意:部分功能在 React Native 环境中可能不可用  name: 'YourAppName',  remotes: {  // 定义远程应用(用于宿主应用)  // remoteName: 'remoteName@http://localhost:8082/mf-manifest.json',  },  exposes: {  // 暴露模块(用于远程应用)  // './Component': './src/Component.tsx',  },  shared: {  // 宿主应用应为所有共享依赖设置 eager: true  react: {  singleton: true,  eager: true,  requiredVersion: '19.1.0',  version: '19.1.0',  },  'react-native': {  singleton: true,  eager: true,  requiredVersion: '0.80.0',  version: '0.80.0',  },  },  },  {  // 这些实验性标志用于修补旧版本包  // 如果项目使用受支持的 React Native 和 Metro 版本,可以省略  flags: {  // 启用修补 React Native 的 HMR Client  unstable_patchHMRClient: true,  // 启用修补 React Native CLI  unstable_patchInitializeCore: true,  // 启用修补 Metro 的运行时 require  unstable_patchRuntimeRequire: true,  },  } );

应用异步边界设置

使用 withAsyncStartup 包装主 App 组件以启用模块联邦运行时。
这会创建一个异步边界,确保在渲染应用组件之前正确初始化模块联邦运行时。

import { withAsyncStartup } from '@module-federation/runtime'; import { AppRegistry } from 'react-native';  // 使用 withAsyncStartup 创建异步边界 // 传入获取 App 组件的函数 // 可选地传入获取备用组件的函数 const WrappedApp = withAsyncStartup(  () => require('./App'),  () => require('./Fallback') // 可选备用组件 );  AppRegistry.registerComponent('YourAppName', WrappedApp);

withAsyncStartup 的作用:

  • 在渲染应用前等待模块联邦运行时初始化
  • 使用 React Suspense 处理异步加载
  • 可选地接受一个备用组件,在初始化期间显示

使用模式

宿主应用

宿主应用从其他应用中消费远程模块:

// 宿主应用 metro.config.js module.exports = withModuleFederation(  mergeConfig(getDefaultConfig(__dirname), config),  {  name: 'HostApp',  remotes: {  'mini-app': 'miniApp@http://localhost:8082/mf-manifest.json',  'another-app': 'anotherApp@http://192.168.1.100:8083/mf-manifest.json',  },  shared: {  react: { singleton: true, eager: true },  'react-native': { singleton: true, eager: true },  },  } );

远程应用(子应用)

远程应用暴露模块供宿主应用使用:

// 远程应用 metro.config.js module.exports = withModuleFederation(  mergeConfig(getDefaultConfig(__dirname), config),  {  name: 'MiniApp',  exposes: {  './Screen': './src/Screen.tsx',  './Component': './src/Component.tsx',  },  shared: {  react: { singleton: true, eager: true },  'react-native': { singleton: true, eager: true },  },  } );

CLI 命令

React Native CLI 集成提供了额外的命令来打包联邦应用:

打包宿主应用

打包消费远程模块的宿主应用:

# iOS 打包 react-native bundle-mf-host --entry-file index.js --platform ios  # Android 打包 react-native bundle-mf-host --entry-file index.js --platform android

打包远程应用

打包暴露模块的远程应用(子应用):

# iOS 打包 react-native bundle-mf-remote --platform ios  # Android 打包 react-native bundle-mf-remote --platform android

这些命令支持与标准 react-native bundle 命令相同的所有选项。

注意:这些命令由 @module-federation/metro-plugin-rnc-cli 包提供。

React Native Enterprise Framework (RNEF) 集成

如果项目使用 React Native Enterprise Framework (RNEF),请在 rnef.config.mjs 中添加模块联邦插件:

import { pluginMetroModuleFederation } from '@module-federation/metro-plugin-rnef'; import { platformAndroid } from '@rnef/platform-android'; import { platformIOS } from '@rnef/platform-ios'; import { pluginMetro } from '@rnef/plugin-metro';  /** @type {import('@rnef/config').Config} */ export default {  bundler: pluginMetro(),  platforms: {  ios: platformIOS(),  android: platformAndroid(),  },  plugins: [pluginMetroModuleFederation()], };

API 参考

withModuleFederation(metroConfig, federationConfig, options?)

包装 Metro 配置以启用模块联邦。

参数

  • metroConfig (MetroConfig) - 现有的 Metro 配置
  • federationConfig (FederationConfig) - 模块联邦配置
  • options (Options) - 可选配置,用于实验性功能

FederationConfig 接口

export interface ModuleFederationConfig {  name: string;  filename?: string;  remotes?: Record<string, string>;  exposes?: Record<string, string>;  shared?: Shared;  shareStrategy?: 'loaded-first' | 'version-first';  plugins?: string[]; }

SharedConfig 接口

export interface SharedConfig {  singleton: boolean;  eager: boolean;  version: string;  requiredVersion: string;  import?: false; }

示例与最佳实践

配置遵循标准的 模块联邦配置格式
关于模块联邦的概念、配置选项和使用模式的完整信息,请参考官方 模块联邦文档

要查看可运行的示例和详细实现指南,请访问 Module Federation Metro 仓库,其中包含多个示例应用,展示了不同的使用模式和集成方式。