Skip to content

Commit

Permalink
chore(metro-config): noop exotic mode (#24927)
Browse files Browse the repository at this point in the history
# Why

Most of the [Exotic
mode](https://blog.expo.dev/drastically-faster-bundling-in-react-native-a54f268e0ed1)
performance benefits have been integrated in the default Expo CLI
bundling pipeline (e.g. [less AST
cloning](facebook/metro#854), [faster worker
creation](facebook/metro#856)), and as such, the
feature no longer needs to be enabled/disabled. Setting `mode: "exotic"`
will no longer have any additional effects over the default.

# Checklist

<!--
Please check the appropriate items below if they apply to your diff.
This is required for changes to Expo modules.
-->

- [ ] Documentation is up to date to reflect these changes (eg:
https://docs.expo.dev and README.md).
- [ ] Conforms with the [Documentation Writing Style
Guide](https://github.com/expo/expo/blob/main/guides/Expo%20Documentation%20Writing%20Style%20Guide.md)
- [ ] This diff will work correctly for `npx expo prebuild` & EAS Build
(eg: updated a module plugin).

---------

Co-authored-by: Expo Bot <34669131+expo-bot@users.noreply.github.com>
  • Loading branch information
2 people authored and marklawlor committed Oct 30, 2023
1 parent e4b6eba commit d2c14e8
Show file tree
Hide file tree
Showing 14 changed files with 44 additions and 176 deletions.
2 changes: 2 additions & 0 deletions packages/@expo/metro-config/CHANGELOG.md
Expand Up @@ -10,6 +10,8 @@

### 💡 Others

- "Exotic mode", `EXPO_USE_EXOTIC`, and `EXPO_USE_FB_SOURCES` have been deprecated and no longer enable any experimental functionality. ([#24927](https://github.com/expo/expo/pull/24927) by [@EvanBacon](https://github.com/EvanBacon))

## 0.14.0 — 2023-10-17

### 🛠 Breaking changes
Expand Down
120 changes: 19 additions & 101 deletions packages/@expo/metro-config/README.md
@@ -1,57 +1,32 @@
<!-- Title -->
<h1 align="center">
👋 Welcome to <br><code>@expo/metro-config</code>
</h1>
# `@expo/metro-config`

<p align="center">A Metro config for running React Native projects with the Metro bundler.</p>
This package contains the default Metro config that is required for bundling Expo apps.

<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 -->
`metro.config.js`

## Exotic
```js
// Learn more https://docs.expo.io/guides/customizing-metro
const { getDefaultConfig } = require('expo/metro-config');

When enabled, exotic mode adds the following assumptions:
/** @type {import('expo/metro-config').MetroConfig} */
const config = getDefaultConfig(__dirname);

- 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.
module.exports = config;
```

### Default Rules
## Exotic

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.
Most of the [Exotic mode](https://blog.expo.dev/drastically-faster-bundling-in-react-native-a54f268e0ed1) performance benefits have been integrated in the default Expo CLI bundling pipeline (e.g. [less AST cloning](https://github.com/facebook/metro/pull/854), [faster worker creation](https://github.com/facebook/metro/pull/856)), and as such, the feature no longer needs to be enabled/disabled. Setting `mode: "exotic"` will no longer have any additional effects over the default.

### Extra Customization
If you'd like to use different transformers (e.g. Sucrase) for different files, you can still create a custom transformer and refine it for your project needs.

> Experimental
### Custom transformers

You can use `@expo/metro-config/transformer` to extend the experimental transformer API.
This can be used for:
> Caution: This is an advanced feature for developers who need to speed up the bundling of very large apps.
- 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.
You can use `@expo/metro-config/transformer` to create a custom multi-rule transformer. This is useful for running fewer transformations on node modules and speeding up bundling.

`metro-exotic-transformer.js`
`metro.transformer.js`

```js
const { createExoticTransformer } = require('@expo/metro-config/transformer');
Expand All @@ -76,15 +51,10 @@ Then use it in your project:
```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',
});
const config = getDefaultConfig(__dirname);

// Use the new transformer
config.transformer.babelTransformerPath = require.resolve('./metro-exotic-transformer');
config.transformer.babelTransformerPath = require.resolve('./metro.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.
Expand All @@ -93,55 +63,3 @@ config.transformer.babelTransformerPath = require.resolve('./metro-exotic-transf

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;
```
1 change: 1 addition & 0 deletions packages/@expo/metro-config/build/ExpoMetroConfig.d.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 2 additions & 5 deletions packages/@expo/metro-config/build/ExpoMetroConfig.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/@expo/metro-config/build/ExpoMetroConfig.js.map

Large diffs are not rendered by default.

2 changes: 0 additions & 2 deletions packages/@expo/metro-config/build/env.d.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 0 additions & 5 deletions packages/@expo/metro-config/build/env.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/@expo/metro-config/build/env.js.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit d2c14e8

Please sign in to comment.