为什么选择 Metro?

编辑页面

了解为什么 Metro 是 React Native 中通用打包的未来,以及它如何帮助开发者。


For the complete documentation index, see llms.txt. Use this Use this file to discover all available pages.

Metro 是 Expo 和 React Native 的官方打包器。它是 Expo 框架中的核心构建工具。打包器包含数以千计的理念与取舍。本文将概述 Expo 围绕 Metro 开发的关键原因,以及它如何帮助开发者。

Meta 官方打包器

Metro 由 Meta 维护,而 Meta 也是 React、React Native、Yoga 和 Hermes 的维护者。它被用于开发世界上一些最大的应用,覆盖应用商店中的所有类别。

Meta 工程师积极开发 Metro,明确要求它能够为他们所有应用进行打包,覆盖 40 万以上的源文件,同时保持快速和可靠。

通过提供一流的 Metro 支持,我们确保 Expo 开发者能够在 Meta 的工具链之间保持连续性,并即时获得新兴功能。这包括:

  • React Fast Refresh 于 2019 年作为 Metro 的一个特性首次引入。React Web 社区在次年通过 Webpack 采用了它。
  • 将 JavaScript 转换为 Hermes 字节码,以实现即时原生启动。
  • React Native DevTools,包括对网络和 JS 调试的一流支持,仅可通过 Metro 和 Hermes 使用。
  • React Compiler 最初作为一个与 Metro 兼容的 Babel 插件发布。

计划加入 Metro 的新功能和即将推出的功能包括:

  • 使用 Static Hermes 将 Flow 代码编译为原生机器码。可在 Tzvetan Mikov 的 Static Hermes 演讲中了解更多。
  • 使用适用于所有平台的通用 React Server Components 实现数据获取、流式传输、React Suspense、服务端渲染以及构建时静态渲染。可在 React Conf 2024 的 Universal React Server Components 演讲中了解更多。

Expo 团队与 Meta 合作,为 Expo Router 开发 Metro,添加了诸如基于文件的路由Web 支持包拆分tree shakingCSSDOM 组件、服务端组件以及 API 路由等功能。

大规模实战检验

世界上几乎每个 React Native 应用都在使用 Metro,这使它成为一个经过大规模项目实战检验的解决方案。无论是个人开发者还是大型公司,它都同样适用。Metro 专为处理 Meta 的大规模应用而设计,这也是它具备通过 Watchman 进行原生文件监视以及共享远程缓存等特性的原因。

按需处理

在开发过程中,Metro 在被请求之前不会执行任何平台相关工作。这使开发者能够在大型项目上工作,而无需为所支持的平台数量付出性能成本。结合激进的缓存和异步路由,开发者可以逐步打包当前正在处理的应用部分。

多维度

与传统打包器会创建多个实例来打包服务端和客户端代码不同,Metro 在不同平台和环境之间(服务端、客户端、DOM 组件)最大化资源复用。这种架构非常适合多平台和服务端开发。

可复用的转换记忆化

Metro 是增量式的,并且可以创建可缓存的转换产物,这些产物可以在不同机器之间复用。这使大型团队能够复用远程构建器的工作成果,这也是 Meta 在所有大型项目中使用的一种技术。

针对自定义运行时优化

虽然其他打包器是围绕网页浏览器的静态规范设计的,但 Metro 针对 React Native 的灵活性进行了优化。这使其能够实现诸如生成 Hermes 字节码编译所需的、受支持语言特性的特定集合等功能,从而在生产环境中实现更快的应用启动。这也将扩展到 Static Hermes,它会将静态类型信息编译为原生应用的机器码。

跨技术支持

Expo 利用 Metro 的技术创建诸如 DOM 组件 之类的新功能。这使得原生应用中的 React 组件可以按需动态打包为一个完整的网站,并继承与父应用相同的所有默认设置。

原生资源导出

与传统打包器不同,后者的最终结果是一个完全托管的应用,Metro 的配置选项支持导出可作为原生产物嵌入独立应用二进制文件中的打包结果。这利用了操作系统特定的优化,例如 Apple 平台上的 xcassets

并发处理

Metro 中所有的 AST 转换都会在所有可用线程上并发执行,从而最大化硬件利用率。

与其他方案的比较

虽然 Metro 是为通用应用开发而设计的,但它经常会与其他仅面向 Web 的打包器进行比较。以下是一些关键差异:

浏览器 ESM 与打包

像 Vite 这样的打包器利用了浏览器内置的 ESM 支持,但由于成千上万级联的网络请求,这种方式在中大型规模下可能导致更慢的实际开发体验。Metro 在本地开发中执行打包,这使开发结果与生产结果更接近,也更适合 React Native 更大的模块数量。

JavaScript 与原生语言

有几种打包器出于性能原因选择用 Rust 编写核心,但这也带来了一些取舍,例如更高的贡献、补丁和开发难度。Metro 根据不同操作采用多种技术的组合:

  • 核心打包器和工具使用 JS/Flow 编写。
  • 文件监视通过 Watchman 使用 C++ 编写,并带有 JS 兜底方案。随后 Watchman 会在你电脑上的各个项目中复用。
  • AST 通过 Hermes parser(WebAssembly)解析为与 Babel 兼容的格式。
  • AST 转换由 Babel 完成。这最大化了开发者的自定义能力。
  • 压缩在原生平台上使用 Hermes,在 Web 上使用 Terser(可选支持 ESBuild)。
  • CSS 解析和压缩使用 LightningCSS(Rust)完成。

这种方式与 Meta 和社区工具保持一致,同时也让开发者更容易进行调试、性能分析和补丁修改。