Metro 打包工具

编辑

了解可自定义的不同 Metro 打包工具配置。


Expo CLI 在 npx expo startnpx expo export 期间使用 Metro 来打包你的 JavaScript 代码和资产。Metro 为 React Native 构建并优化,广泛用于 Facebook 和 Instagram 等大型应用程序。

自定义

你可以通过在项目根目录创建 metro.config.js 文件来自定义 Metro 打包工具。此文件应导出一个扩展 expo/metro-configMetro 配置。导入 expo/metro-config 而不是 @expo/metro-config 以确保版本一致性。

运行以下命令以生成模板文件:

Terminal
npx expo customize metro.config.js

metro.config.js 文件如下所示:

metro.config.js
const { getDefaultConfig } = require('expo/metro-config'); const config = getDefaultConfig(__dirname); module.exports = config;

有关更多信息,请参阅 metro.config.js 文档

资产

Metro 将文件解析为源代码或资产。源代码是 JavaScript、TypeScript、JSON 和其他应用程序使用的文件。资产 是图像、字体和其他不应由 Metro 转换的文件。为了适应大规模代码库,Metro 要求所有源代码和资产的扩展必须在启动打包工具之前明确定义。这是通过将 resolver.sourceExtsresolver.assetExts 选项添加到 Metro 配置中来完成的。默认情况下,包含以下扩展:

assetExts 添加更多文件扩展名

最常见的自定义是向 Metro 添加额外的资产扩展名。

metro.config.js 文件中,将文件扩展名(不带前导 .)添加到 resolver.assetExts 数组:

metro.config.js
const { getDefaultConfig } = require('expo/metro-config'); const config = getDefaultConfig(__dirname); config.resolver.assetExts.push( // 为 SQLite 数据库添加对 `.db` 文件的支持 'db' ); module.exports = config;

别名

有时你希望将一个导入重定向到另一个模块或文件。这称为别名。由于 Metro 同时为多个平台打包,我们建议使用自定义解析器来处理别名。

在以下示例中,我们将为 old-module 添加一个别名指向 new-module

metro.config.js
const { getDefaultConfig } = require('expo/metro-config'); /** @type {import('expo/metro-config').MetroConfig} */ const config = getDefaultConfig(__dirname); const ALIASES = { 'old-module': 'new-module', }; config.resolver.resolveRequest = (context, moduleName, platform) => { // 确保你调用默认解析器。 return context.resolveRequest( context, // 如果存在别名则使用别名。 ALIASES[moduleName] ?? moduleName, platform ); }; module.exports = config;

如果你只想在某个平台上应用别名,可以检查 platform 参数:

metro.config.js
config.resolver.resolveRequest = (context, moduleName, platform) => { if (platform === 'web') { // 仅在为 Web 打包时使用别名。 return context.resolveRequest(context, ALIASES[moduleName] ?? moduleName, platform); } // 确保你调用默认解析器。 return context.resolveRequest(context, moduleName, platform); };

下次重启开发服务器时你会看到这些更改。解析不会被缓存,并且不需要 --clear 标志进行更新。如果你使用基于转换的系统,如 babel-plugin-module-resolver,你需要清除缓存以查看已应用的更改。

自定义 Metro 解析

了解更多关于你的项目中高级 Metro 解析的信息。

包分割

Expo CLI 会根据异步导入自动分割包(仅限Web)。

此技术可以与 Expo Router 一起使用,以根据 app 目录中的路由文件自动分割包。它将只加载当前路由所需的代码,并在用户导航到不同页面时延迟加载额外的 JavaScript。有关更多信息,请参见 异步路由

树摇

树摇

了解 Expo CLI 如何优化生产 JavaScript 包。

代码压缩

压缩 JavaScript

了解如何使用 Metro 打包工具自定义 JavaScript 压缩过程。

Web 支持

Expo CLI 支持使用 Metro 打包网站。这是用于原生应用程序的相同打包工具,并且设计为跨平台通用。它是 Web 项目的推荐打包工具。

Expo webpack 与 Expo Metro

如果你之前使用已弃用的 @expo/webpack-adapter 编写了网站,请查看 迁移指南对比图表

向 Metro 添加 Web 支持

修改你的 app 配置 以使用 expo.web.bundler 字段启用该功能:

app.json
{ "expo": { "web": { "bundler": "metro" } } }

开发

要启动开发服务器,运行以下命令:

Terminal
npx expo start --web

或者,在 Expo CLI 终端 UI 中按 W

静态文件

Expo 的 Metro 实现支持通过将静态文件放置在根 public/ 目录中,从开发服务器托管静态文件。这与许多其他 Web 框架类似。

当使用 npx expo export 导出时,public 目录的内容将被复制到 dist/ 目录。这意味着你的应用可以期望相对于主机 URL 获取这些资产。最常见的例子是 public/favicon.ico,这通常用于网站渲染标签图标。

你可以通过在项目中创建 public/index.html 文件来覆盖 Metro Web 的默认 index.html

未来,这将能够在所有平台上通用,支持 EAS 更新托管。目前,此功能仅基于用于原生应用的静态主机,旧版 Expo 服务更新不支持此功能。

TypeScript

Expo 的 Metro 配置支持项目的 tsconfig.json(或 jsconfig.json)文件中的 compilerOptions.pathscompilerOptions.baseUrl 字段。这使项目中的绝对导入和别名成为可能。有关更多信息,请参见 TypeScript 指南。

此功能在裸项目中需要额外设置。有关更多信息,请参见 Metro 设置指南

CSS

Metro Web CSS 指南

了解如何在使用 Expo CLI 和 Metro 打包的网页中使用 CSS。