You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

148 lines
5.8 KiB

<!-- Title -->
<h1 align="center">
👋 Welcome to <br><code>@expo/metro-config</code>
</h1>
<p align="center">A Metro config for running React Native projects with the Metro bundler.</p>
<p align="center">
<img src="https://flat.badgen.net/packagephobia/install/@expo/metro-config">
<a href="https://www.npmjs.com/package/@expo/metro-config">
<img src="https://flat.badgen.net/npm/dw/@expo/metro-config" target="_blank" />
</a>
</p>
<!-- Body -->
## Exotic
When enabled, exotic mode adds the following assumptions:
- Resolver Fields: `browser, main`
- The `react-native` field in module `package.json` is **NOT** supported.
- Packages using `react-native-builder-bob` will default to using the CommonJS setting in exotic. If you need to modify your Node modules manually, be sure to change the files in your `lib/commonjs/` folder.
- Extensions: `ts, tsx, js, jsx, json, cjs`
- `cjs` is added.
- `.babelrc` support is removed in favor of `babel.config.js`.
- `x_facebook_sources` is toggled off by default.
### Default Rules
1. Modules with `.*/lib/commonjs/` are skipped.
2. React Native is transformed with Sucrase to remove flow types and other unsupported language features.
- If the React Native team transpiles react-native before shipping, we can remove this step.
3. Expo modules are transformed with Sucrase to remove import/export syntax. This is temporary while we figure out how to add ESModule support to the native runtime.
- This is for improved tree shaking.
4. Known community modules (especially ones included in Expo Go) are transformed using a more expensive Sucrase preset
- We may add support for extending this list in the future.
5. All other node modules are skipped.
6. All remaining code is assumed to be application code and transpiled with your local Babel preset.
- "Victory Native" packages use too many language features so they are transpiled with Babel.
### Extra Customization
> Experimental
You can use `@expo/metro-config/transformer` to extend the experimental transformer API.
This can be used for:
- Adding extra modules that need to be transpiled locally (`transpileModules`).
- Adding extra `nodeModulesPaths` for monorepo support.
- Adding support for the `react-native` main resolver field back.
`metro-exotic-transformer.js`
```js
const { createExoticTransformer } = require('@expo/metro-config/transformer');
module.exports = createExoticTransformer({
transpileModules: ['@stripe/stripe-react-native'],
// You can uncomment the following lines to add any extra node_modules paths in a monorepo:
// nodeModulesPaths: [
// 'node_modules',
// // Generally you'll add this when your config is in `apps/my-app/metro.config.js`
// '../../node_modules',
// // If you have custom packages in a `packages/` folder
// '../../packages',
// ],
});
```
Then use it in your project:
`metro.config.js`
```js
const { getDefaultConfig } = require('@expo/metro-config');
const config = getDefaultConfig(__dirname, {
// Initialize in exotic mode.
// If you want to preserve `react-native` resolver main field, and omit cjs support, then leave this undefined
// and skip setting the `EXPO_USE_EXOTIC` environment variable.
mode: 'exotic',
});
// Use the new transformer
config.transformer.babelTransformerPath = require.resolve('./metro-exotic-transformer');
// Optionally, you can add support for the `react-native` resolver field back
// doing this will increase bundling time and size as many community packages ship untransformed code using this feature.
// Other packages like `nanoid` use the field to support `react-native` so you may need to enable it regardless.
// defaultConfig.resolver.resolverMainFields.unshift('react-native');
module.exports = config;
```
### Source Maps
Metro bundler adds an undocumented extension to source maps which provides slightly different names for anonymous functions. The source map sizes increase a lot by adding the `x_facebook_sources` object, and the net transformation time also increases by a noticeable amount. By default, exotic disables this feature. The feature can be re-enabled with `EXPO_USE_FB_SOURCES`. Here are the results:
<table>
<tr>
<th>Enabled</th>
<th>Disabled</th>
</tr>
<tr>
<td>iOS Bundling: <b>7664ms</b></td>
<td>iOS Bundling: <b>6875ms</b></td>
</tr>
<tr>
<td><img src="https://user-images.githubusercontent.com/9664363/134078785-c9b0d93d-3dfb-4552-b786-b45059e10c3b.png" width="200" /></td>
<td><img src="https://user-images.githubusercontent.com/9664363/134078781-9f79e9d8-56c7-4e20-952f-8214deb3f0ca.png" width="200" /></td>
</tr>
</table>
- Most error reporting services don't support `x_facebook_sources` so the larger size mostly just increases hosting costs (when uploaded).
- Documentation for `x_facebook_sources` is not provided.
Cite: [#3861](https://github.com/expo/expo-cli/pull/3861)
### Troubleshooting
You should see the following log when Exotic is enabled:
> Unstable feature **EXPO_USE_EXOTIC** is enabled. Bundling may not work as expected, and is subject to breaking changes.
Or if `EXPO_DEBUG=1` is enabled, you'll see exotic mode in the settings breakdown.
If you don't see this message, check to ensure your `metro.config.js` is using `@expo/metro-config` and the version is at least `0.2.2`.
The transformer can be debugged using the environment variable: `DEBUG=expo:metro:exotic-babel-transformer` or `DEBUG=expo:metro:*`
### Adding Resolver Fields
You can add the `react-native` field back manually when exotic mode is enabled, we will investigate adding it back after more community packages have had time to adjust to transforming their code ahead of time.
`metro.config.js`
```js
const { getDefaultConfig } = require('@expo/metro-config');
const config = getDefaultConfig(__dirname);
config.resolver.resolverMainFields.unshift('react-native');
module.exports = config;
```