Metro 打包器
了解可定制的不同 Metro 打包器配置。
Expo CLI 在 npx expo start 和 npx expo export 期间使用 Metro 来打包你的 JavaScript 代码和资源。Metro 为 React Native 构建和优化,并用于像 Facebook 和 Instagram 这样的大型应用。
🌐 Expo CLI uses Metro during npx expo start and npx expo export to bundle your JavaScript code and assets. Metro is built and optimized for React Native and used for large-scale applications such as Facebook and Instagram.
定制
🌐 Customizing
你可以通过在项目根目录下创建 metro.config.js 文件来自定义 Metro 打包器。该文件应导出一个扩展 expo/metro-config 的 Metro 配置。请导入 expo/metro-config 而不是 @expo/metro-config 以确保版本一致性。
🌐 You can customize the Metro bundler by creating a metro.config.js file at the root of your project. This file should export a Metro configuration that extends expo/metro-config. Import expo/metro-config instead of @expo/metro-config to ensure version consistency.
运行以下命令生成模板文件:
🌐 Run the following command to generate the template file:
- npx expo customize metro.config.jsmetro.config.js 文件内容如下:
🌐 The metro.config.js file looks as below:
const { getDefaultConfig } = require('expo/metro-config'); const config = getDefaultConfig(__dirname); module.exports = config;
有关更多信息,请参阅 metro.config.js 文档。
🌐 See metro.config.js documentation for more information.
资源
🌐 Assets
Metro 将文件解析为源代码或资源。源代码包括 JavaScript、TypeScript、JSON 以及应用使用的其他文件。资源 是图片、字体和其他不应被 Metro 转换的文件。为了适应大规模代码库,Metro 要求在启动打包器之前显式定义源代码和资源的所有扩展名。这通过将 resolver.sourceExts 和 resolver.assetExts 选项添加到 Metro 配置中来实现。默认情况下,包括以下扩展名:
🌐 Metro resolves files as either source code or assets. Source code is JavaScript, TypeScript, JSON, and other files used by your application. Assets are images, fonts, and other files that should not be transformed by Metro. To accommodate large-scale codebases, Metro requires all extensions for both source code and assets to be explicitly defined before starting the bundler. This is done by adding the resolver.sourceExts and resolver.assetExts options to the Metro configuration. By default, the following extensions are included:
向 assetExts 添加更多文件扩展名
🌐 Adding more file extensions to assetExts
最常见的定制是包含 Metro 的额外资源扩展。
🌐 The most common customization is to include extra asset extensions to Metro.
在 metro.config.js 文件中,将文件扩展名(不带前导 .)添加到 resolver.assetExts 数组中:
🌐 In the metro.config.js file, add the file extension (without a leading .) to resolver.assetExts array:
const { getDefaultConfig } = require('expo/metro-config'); const config = getDefaultConfig(__dirname); config.resolver.assetExts.push( // Adds support for `.db` files for SQLite databases 'db' ); module.exports = config;
别名
🌐 Aliases
有时你希望某个导入被重定向到另一个模块或文件,这被称为别名。由于 Metro 同时为多平台打包的方式,我们建议使用自定义解析器来处理别名。
🌐 Sometimes you want an import to be redirected to another module or file. This is called an alias. Due to the way Metro bundles for multiple platforms simultaneously, we recommend using a custom resolver to handle aliases.
在下面的示例中,我们将为 old-module 添加一个别名 new-module:
🌐 In the following example, we'll add an alias for old-module to new-module:
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) => { // Ensure you call the default resolver. return context.resolveRequest( context, // Use an alias if one exists. ALIASES[moduleName] ?? moduleName, platform ); }; module.exports = config;
如果你只想在某个平台上使用别名,你可以检查 platform 参数:
🌐 If you want to only apply the alias on a certain platform, you can check the platform argument:
config.resolver.resolveRequest = (context, moduleName, platform) => { if (platform === 'web') { // The alias will only be used when bundling for the web. return context.resolveRequest(context, ALIASES[moduleName] ?? moduleName, platform); } // Ensure you call the default resolver. return context.resolveRequest(context, moduleName, platform); };
下次重启开发服务器时,你将看到更改。解析结果从不缓存,也不需要 --clear 标志来更新。如果你使用像 babel-plugin-module-resolver 这样的基于转换的系统,你需要清除缓存才能看到应用的更改。
🌐 You will see the changes the next time you restart the dev server. Resolutions are never cached and do not need the --clear flag to update. If you use a transform-based system like babel-plugin-module-resolver, you will need to clear the cache to see changes applied.
了解有关在你的项目中高级 Metro 解析的更多信息。
打包分裂
🌐 Bundle splitting
Expo CLI 会根据异步导入自动拆分 bundle(仅限 Web 应用)。
🌐 Expo CLI automatically splits bundles based on async imports (web-only).
这一技术可以与 Expo Router 一起使用,根据 app 目录中的路由文件自动拆分包。它只会加载当前路由所需的代码,并延迟加载额外的 JavaScript,直到用户导航到不同的页面。更多信息请参见 异步路由。
🌐 This technique can be used with Expo Router to automatically split the bundle based on route files in the app directory. It will only load the code required for the current route, and defer loading additional JavaScript until the user navigates to different pages. See Async Routes for more information.
摇树
🌐 Tree shaking
了解 Expo CLI 如何优化生产 JavaScript 包。
缩小化
🌐 Minification
了解如何使用 Metro 打包程序在 Expo CLI 中自定义 JavaScript 缩小流程。
Web 支持
🌐 Web support
Expo CLI 支持使用 Metro 打包网站。Metro 是用于原生应用的同一个打包工具,并且设计为跨平台通用。它是 Web 项目的推荐打包工具。
🌐 Expo CLI has support for bundling websites using Metro. This is the same bundler used for native apps, and it is designed to be universal across platforms. It is the recommended bundler for web projects.
Expo webpack 与 Expo Metro
🌐 Expo webpack versus Expo Metro
如果你之前使用已弃用的 @expo/webpack-adapter 编写了网站,请参阅 迁移指南 和 对比图表。
🌐 If you previously wrote your website using the deprecated @expo/webpack-adapter, see the migration guide and comparison chart.
为 Metro 添加 Web 支持
🌐 Adding Web support to Metro
修改你的应用配置,使用 expo.web.bundler 字段启用此功能:
🌐 Modify your app config to enable the feature using the expo.web.bundler field:
{ "expo": { "web": { "bundler": "metro" } } }
开发
🌐 Development
要启动开发服务器,请运行以下命令:
🌐 To start the development server run the following command:
- npx expo start --web或者,在 Expo CLI 终端界面中按 W 。
静态文件
🌐 Static files
Expo 的 Metro 实现支持通过将静态文件放在根目录 public/ 中,从开发服务器托管它们。这与许多其他 web 框架类似。
🌐 Expo's Metro implementation supports hosting static files from the dev server by putting them in the root public/ directory. It is similar to many other web frameworks.
使用 npx expo export 导出时,public 目录的内容会被复制到 dist/ 目录中。这意味着你的应用可以期望相对于主机 URL 获取这些资源。最常见的例子是 public/favicon.ico,网站会使用它来显示标签页图标。
🌐 When exporting with npx expo export, the contents of the public directory are copied into the dist/ directory. It means your app can expect to fetch these assets relative to the host URL. The most common example of this is the public/favicon.ico which is used by websites to render the tab icon.
你可以通过在你的项目中创建一个 public/index.html 文件来覆盖 Metro web 中的默认 index.html。
🌐 You can overwrite the default index.html in Metro web by creating a public/index.html file in your project.
将来,这将在使用 EAS Update 托管的平台上普遍适用。目前,该功能仅限于基于原生应用使用的静态托管的网络,例如,旧版 Expo 服务更新不支持此功能。
🌐 In the future, this will work universally across platforms with EAS Update hosting. Currently, the feature is web-only based on the static host used for the native app, for example, the legacy Expo service updates do not support this feature.
TypeScript
Expo 的 Metro 配置支持项目的 tsconfig.json(或 jsconfig.json)文件中的 compilerOptions.paths 和 compilerOptions.baseUrl 字段。这使得项目中可以使用绝对导入和别名。有关更多信息,请参阅 TypeScript 指南。
🌐 Expo's Metro config supports the compilerOptions.paths and compilerOptions.baseUrl fields in the project's tsconfig.json (or jsconfig.json) file. This enables absolute imports and aliases in the project. See TypeScript guide for more information.
此功能在裸项目中需要额外的设置。有关更多信息,请参阅 Metro 设置指南。
🌐 This feature requires additional setup in bare projects. See the Metro setup guide for more information.
CSS
了解如何在使用 Expo CLI 和 Metro 打包工具打包的网页中使用 CSS。