Metro Bundler:是什么、项目构建及工作原理

作者: IT Sectr 发布日期: 2026-07-06 阅读时间: 8 分钟

Metro Bundler 是 Meta 开发的专用 JavaScript 打包器,专为 React Native 设计并构成框架的核心。根据 React Native 0.76(2025)的官方文档,Metro 提供增量构建和 Fast Refresh,并支持 .native.js、.ios.js 和 .android.js 平台扩展的模块解析。与 Webpack 不同,Metro 不使用长期存在的 module graph 缓存——而是在文件更改时每次都重建图,这在开发时提供了即时热重载

要点

  • Metro Bundler — React Native 的官方 JavaScript 打包器,支持平台扩展
  • Fast Refresh — 代码更改时热重载并保留组件状态
  • Haste Module System — 用于增量构建的稳定模块 ID 系统
  • 平台扩展 — .native.js、.ios.js、.android.js 用于按平台分离代码
  • Hermes 字节码 — 直接为 Hermes 引擎构建字节码的模式

什么是 Metro Bundler

Metro Bundler 是一个开源 JavaScript 打包器,由 Meta 为 React Native 开发,默认用于框架的所有项目。Metro 的任务是获取项目的 JavaScript 代码及其依赖项,构建一个或多个在设备上执行的包。与通用打包器(Webpack、Rollup、Parcel)不同,Metro 针对移动开发的特性进行了优化:最小的构建时间、开发期间的增量更新以及与平台模块(Objective-C、Swift、Java、Kotlin 原生模块)的正确协作。Metro 随 React Native CLI 提供,无需单独安装。从 React Native 0.72 开始,Metro 0.80+ 版本支持模块的并行转译,在多核处理器上将构建速度提升高达 40%。

Metro 架构:Resolver、Transformer 和 Bundler

Metro 的架构分为三个独立组件:ResolverTransformerBundler。Resolver 负责搜索和解析模块——它读取 import/require 表达式,考虑平台扩展找到相应文件,并返回绝对路径。Transformer 执行转译:应用 Babel 及其预设和插件,将 JSX、TypeScript 或 Flow 转换为纯 JavaScript。Bundler 是最后阶段:它从 Resolver 接收依赖关系图,从 Transformer 接收转换后的文件,然后将它们序列化到一个或多个包(module bundles)中。分为三个步骤使 Metro 能够缓存每个阶段的结果:如果只有一个文件发生更改,Resolver 和 Bundler 可以对其余模块使用缓存,这在开发模式下使构建速度提升高达 10 倍。

Resolver:模块解析和平台感知搜索

Resolver 在 Metro 中实现了模块解析算法,部分兼容 Node.js module resolution。与 Node.js 的主要区别——支持平台扩展:require('./Component') 按指定的优先级顺序查找 Component.native.js、Component.ios.js、Component.android.js。Resolver 还支持 package.json 中的 "react-native" 字段,用于将模块映射到替代实现——这是具有平台代码的库的标准机制。如果未找到文件,Resolver 会抛出带有完整搜索堆栈的错误。

Transformer:Babel 和转译

Transformer 在 Metro 内部使用带有 metro-react-native-babel-preset 预设的 Babel。标准配置包括:将 JSX 转换为 React.createElement、支持 TypeScript(移除类型)、支持 Flow 以及现代 JavaScript 标准(async/await、optional chaining、nullish coalescing)的 polyfill。Transformer 以并行模式工作:每个模块独立转译,使用工作进程池(默认数量与 CPU 数量相对应)。从 Metro 0.80 开始,支持 Granular Transformer Cache——在单个文件级别使缓存失效。

Metro 中的平台扩展

Metro 的关键特性之一是支持平台文件扩展名。一个 React Native 项目可以包含一个模块的三个版本:Component.ios.js(iOS)、Component.android.js(Android)和 Component.native.js(两个平台)。在导入 require('./Component') 时,Resolver 会根据目标构建平台自动选择正确的版本。这允许编写平台相关代码,而无需 Platform.OS 条件构造。优先级顺序:name.platform.js > name.native.js > name.js。.native.js 扩展用于在两个平台上都工作但与 Web 不兼容的通用代码。.ios.js 和 .android.js 扩展用于实现特定功能——导航、手势、文件系统操作。Metro 通过 resolver.sourceExts 配置支持自定义扩展名。

js
// metro.config.js — sourceExts 和 watchFolders 设置
const config = {
  resolver: {
    sourceExts: ['jsx', 'js', 'tsx', 'ts', 'json'],
    platformExtensions: ['ios', 'android', 'native'],
  },
  transformer: {
    babelTransformerPath: require('metro-react-native-babel-transformer'),
  },
  watchFolders: [path.resolve('../shared')],
};

Metro 中的热重载和 Fast Refresh

Fast Refresh 是构建在 Metro 之上的 React Native 热重载机制。当开发者更改文件时,Metro 仅重新转译修改后的模块,并通过 WebSocket 将更新发送到应用程序。Fast Refresh 在不重新加载整个应用程序的情况下更新界面,如果仅更改了 JSX 或样式,则保留 React 组件的状态。如果更改了包含 hooks 或状态的代码,Fast Refresh 仅对更改的组件执行重新挂载。Metro 支持两种模式:Hot Module Replacement(HMR)用于即时替换模块,以及 Live Reload 用于在原生模块或配置更改时完全重新加载应用程序。Fast Refresh 在 React Native 0.76 中默认启用,无需额外配置——只需运行 npx react-native start 即可。

模式速度保留状态触发器
Fast Refresh200-500msJS/TS 文件更改
HMR100-300msCSS/样式更改
Live Reload1-3s原生配置更改
Full Rebuild10-60spodspec/build.gradle 更改

Metro 配置:metro.config.js

metro.config.js 是 Metro 的配置文件,位于 React Native 项目的根目录。它配置:resolver(sourceExts、platformExtensions、extraNodeModules)、transformer(babelTransformerPath、minifierConfig)、server(port、host、enableFastRefresh)和 watcher(watchFolders、healthCheck)。标准 Metro 配置继承自 @react-native/metro-config(React Native 0.76+)包。对于具有 monorepo 的项目,添加 watchFolders——这将允许 Metro 跟踪项目根目录之外的包中的更改。要配置 sourceExts,为自定义转换器添加 'svg''png''gql'。Metro 支持通过 async function 进行异步配置——这对于基于环境动态生成配置非常有用。

通过配置优化构建

优化 Metro 构建从正确的缓存配置开始。将 maxWorkers 设置为 CPU 数量减 1。对于发布版本,在 CI 上使用 resetCache。最小化 sourceExts——额外的扩展名会减慢模块解析速度。对于大型项目,仅将 watchFolders 配置到必要的目录。Metro 支持 Hermes 字节码压缩,其包大小比标准 Terser 更小——使用 minifierPath'metro-minify-terser'

Hermes 打包:构建字节码

Metro 支持直接构建 Hermes 字节码的模式——跳过 JavaScript AST 阶段。使用 HermesTransformer 构建时,模块被编译为 HBC(Hermes 字节码)而不是纯 JavaScript。这带来:更小的包大小(减少 30-40%)、更快的应用程序启动(加快 20-30%)和更低的内存消耗。要激活,在 metro.config.js 中设置 hermesCommand,并在 build.gradle(Android)或 Podfile(iOS)中激活 Hermes 标志。Hermes 包的构建分两个阶段进行:首先 Metro 构建 JavaScript 包,然后 Hermes CLI 将其转换为 HBC。从 React Native 0.70 开始,Hermes 是 Android 上的默认引擎,在 iOS 上需要显式激活。

Metro 对比 Webpack:方法比较

MetroWebpack 之间的差异源于不同的目标。Webpack 是一个面向 Web 的通用打包器,拥有庞大的插件和加载器生态系统。Metro 是一个面向 React Native 的专用打包器,其优先级是增量构建速度和与原生模块的正确协作。Webpack 使用具有智能缓存失效的长期模块图——这提供了 Web 上的快速重新构建,但给平台扩展带来了问题。Metro 不在构建之间缓存图,而是每次都构建它——这简化了平台扩展和 Haste 模块的处理。Webpack 支持带有 chunk 的动态导入,Metro 也支持——通过 React.lazy() 和 Suspense,但限制为一个活动请求。Metro 的生态系统要小得多:没有 style-loader、css-loader、file-loader 的替代品——这些任务在 React Native 中以不同的方式解决。

何时选择 Metro

Metro 是 React Native 项目的唯一正确选择。Webpack 开箱即不支持平台感知解析,使用 Webpack 配置 React Native 需要大量努力(haul bundler、expo web packager)。Metro 集成到 React Native CLI 中,得到 Meta 官方团队的支持,并随每个 React Native 版本获得更新。对于 React Native Web 项目,可以将 Webpack 用于 Web 构建,同时保留 Metro 用于移动端包。

常见问题

如何清除 Metro Bundler 缓存?

运行 npx react-native start --reset-cache 或删除项目根目录中的 $TMPDIR/metro-* 文件夹和 .metro-health-check* 目录。替代方案:npx react-native clean——此命令清除所有临时 Metro 文件,包括 Babel 缓存和 Haste 映射。清除后,首次构建将是完整的(60-120 秒),但后续增量构建将恢复正常速度。

为什么 Metro 看不到 node_modules 中的模块?

检查包是否存在于 package.json dependencies(而非 devDependencies)中。如果模块位于 monorepo 中,请将路径添加到 metro.config.js 的 watchFolders中。Metro 默认不跟随符号链接——使用 resolver.extraNodeModules 进行显式映射。对于 Yarn PnM,设置 resolver.useWatchmanfalse。如果模块使用平台扩展,请确保 .ios.js 或 .android.js 文件存在于指定路径中。

如何在大型项目中加速 Metro 构建?

将 metro.config.js 中的 maxWorkers 增加到 CPU 数量减 1。仅将 watchFolders 配置到必要的目录。对生产构建使用 Hermes 字节码——这通过跳过 JS 压缩加速最终构建。对于开发,启用 Fast Refresh(默认已启用)。将 sourceExts 限制为仅必要的扩展名。考虑通过懒加载将包拆分为多个 chunk。

Metro 可以用于 Web 项目吗?

技术上可以,但不推荐。Metro 未针对 Web 构建进行优化:不支持 CSS、HTML、图像作为模块,没有浏览器级别的动态导入代码拆分。对于 Web,请使用 Webpack、Vite 或 Parcel。Metro 是 React Native 的专用解决方案,将其适配到 Web 的尝试将导致性能损失和加载器生态系统的缺失。

Metro 与 Re.Pack 有何不同?

Re.Pack 是一个社区工具,用于在 React Native 项目中用 Webpack 替换 Metro。它提供对 Webpack 加载器生态系统(css-loader、svg-loader)和高级代码拆分的访问。然而,Re.Pack 配置更复杂,不受 Meta 官方支持,并且不保证与新版 React Native 的兼容性。Metro 仍然是唯一官方支持的打包器,这提供了稳定性和每个版本的兼容性保证。

总结

  • Metro Bundler — 具有 Resolver-Transformer-Bundler 架构的 React Native 官方 JavaScript 打包器
  • 平台扩展(.ios.js、.android.js、.native.js)— 分离平台代码的关键功能
  • Fast Refresh — 通过 WebSocket 工作的保留组件状态的热重载
  • 配置通过 metro.config.js:sourceExts、watchFolders、maxWorkers 用于构建优化
  • Hermes 字节码 — 为更快启动和更小包大小的字节码构建模式
  • Resolver 使用 Haste Module System 和平台感知解析——与 Webpack 不兼容
  • Transformer 通过 Babel 与工作进程池并行工作
  • Metro 是 React Native CLI 的一部分,启动无需单独安装或配置

我们将开发一款交钥匙移动应用程序

IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。

讨论项目

另请阅读