Skip to content
雲里
里雾

Metro 三阶段流水线与配置

metro 开发 更新于 2026/4/13

本页介绍 Metro bundler 的 Resolution → Transformation → Serialization 三阶段流水线,说明各阶段对应的 metro.config.js 配置字段,以及缓存机制和 Fast Refresh 的工作原理。

Metro 是什么

Metro 是 React Native 官方的 JavaScript bundler,由 Meta 开发,专为移动端设计。它的核心职责和 webpack/Vite 类似——把分散的 JS/TS 模块打成一个(或多个)bundle——但针对 RN 开发体验做了优化:超快的增量构建、HMR、对 require 的动态分析。


三阶段流水线

1. Resolution(依赖解析)

从入口文件出发,递归查找所有 import/require,建立依赖图(dependency graph)。

关键行为:

2. Transformation(模块转换)

对依赖图里每个文件独立做转换,输出 Metro 可以序列化的模块格式。

关键行为:

3. Serialization(序列化打包)

把转换后的模块拼装成最终产物。

关键行为:


metro.config.js 字段对应阶段

const { getDefaultConfig } = require('expo/metro-config')

const config = getDefaultConfig(__dirname)

// ——— Resolution 阶段 ———
config.resolver.sourceExts.push('svg')          // 新增可解析扩展名
config.resolver.assetExts.push('glb')           // 3D 资产
config.resolver.extraNodeModules = { ... }       // 模块别名

// ——— Transformation 阶段 ———
config.transformer.babelTransformerPath = '...'  // NativeWind 等库在这里注入
config.transformer.minifierPath = '...'          // 替换压缩器(默认 terser)

// ——— Serialization 阶段 ———
config.serializer.customSerializer = (...)       // 自定义 bundle 输出格式

module.exports = config

配置文件调用链

pnpm start
  └─ Expo CLI
       读取 app.json(plugins、platforms、sdkVersion)
       注入 Expo 特有 resolver/transformer(如 expo-modules-core)
       └─ Metro(metro.config.js)
            每个模块调用 Transformation 时
            └─ Babel(babel.config.js)
                 NativeWind preset 激活时
                 └─ NativeWind(读取 tailwind.config.js 生成工具类 token)

重要细节:Expo SDK 54 默认不生成 metro.config.js 和 babel.config.js。Expo CLI 内置了对应的默认配置(通过 expo/metro-configbabel-preset-expo 提供)。只有当你需要覆盖默认行为时才创建这两个文件,否则不需要。


缓存机制

Metro 对 Transformation 阶段的结果做文件级缓存。

pnpm start --reset-cache
# 或
pnpm expo start --clear

HMR / Fast Refresh 原理

Fast Refresh 是 Metro + React 共同实现的功能,不是单独的工具。

工作流程:

  1. Metro 监听文件系统变化(FSWatcher)
  2. 文件变更时,只对变更文件及其受影响的依赖重新跑 Transformation
  3. 通过 WebSocket 把变更的模块 patch 推送到 Expo Dev Client
  4. React 的 Fast Refresh runtime 在 JS 线程接收 patch,用新模块替换旧模块
  5. 如果变更的文件只包含 React 组件(没改 hook/class 结构),组件状态被保留;如果改了 hook 顺序或 class 结构,状态被重置

Fast Refresh 的”保留状态”能力依赖 React 内部的 reconciler——它知道哪些状态可以安全保留。这是 webpack HMR 做不到的(webpack HMR 的状态保留需要手写 module.hot.accept 回调)。


常见排查

现象原因解决
改了配置文件但不生效Metro 缓存旧的 transformer 结果--reset-cache
NativeWind class 不生效tailwind.config.js content 路径没覆盖到文件检查 glob 路径
Cannot find moduleresolver.sourceExts 缺少扩展名在 metro.config.js 添加
bundle 很慢依赖图太大,maxWorkers 不够METRO_MAX_WORKERS=8 pnpm start

参见

参考

版本说明