From e43b0b82362f50e3d7f32cdf813b12e984b2de4b Mon Sep 17 00:00:00 2001 From: Alex Hunt Date: Fri, 23 Jun 2023 15:45:38 +0100 Subject: [PATCH] [docs] Add Metro configuration guide, update Metro config references --- docs/metro.md | 104 ++++++++++++++++++ docs/ram-bundles-inline-requires.md | 20 ++-- website/sidebars.json | 1 + website/versioned_docs/version-0.72/metro.md | 104 ++++++++++++++++++ .../ram-bundles-inline-requires.md | 20 ++-- .../version-0.72-sidebars.json | 1 + 6 files changed, 230 insertions(+), 20 deletions(-) create mode 100644 docs/metro.md create mode 100644 website/versioned_docs/version-0.72/metro.md diff --git a/docs/metro.md b/docs/metro.md new file mode 100644 index 00000000000..bf47d13ce54 --- /dev/null +++ b/docs/metro.md @@ -0,0 +1,104 @@ +--- +id: metro +title: Metro +--- + +React Native uses [Metro](https://facebook.github.io/metro/) to build your JavaScript code and assets. + +## Configuring Metro + +Configuration options for Metro can be customized in your project's `metro.config.js` file. This can export either: + +- **An object (recommended)** that will be merged on top of Metro's internal config defaults. +- [**A function**](#advanced-using-a-config-function) that will be called with Metro's internal config defaults and should return a final config object. + +:::tip +Please see [**Configuring Metro**](https://facebook.github.io/metro/docs/configuration) on the Metro website for documentation on all available config options. +::: + +In React Native, your Metro config should extend either [@react-native/metro-config](https://www.npmjs.com/package/@react-native/metro-config) or [@expo/metro-config](https://www.npmjs.com/package/@expo/metro-config). These packages contain essential defaults necessary to build and run React Native apps. + +Below is the default `metro.config.js` file in a React Native template project: + + +```js +const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config'); + +/** + * Metro configuration + * https://facebook.github.io/metro/docs/configuration + * + * @type {import('metro-config').MetroConfig} + */ +const config = {}; + +module.exports = mergeConfig(getDefaultConfig(__dirname), config); +``` + +Metro options you wish to customize can be done so within the `config` object. We strongly recommend defining all config values statically within this file. + +### Advanced: Using a config function + +Exporting a config function is an opt-in to managing the final config yourself — **Metro will not apply any internal defaults**. This pattern can be useful when needing to read the base default config object from Metro or to set options dynamically. + +:::info +**From @react-native/metro-config `0.72.1`**, it is no longer necessary to use a config function to access the complete default config. See the **Tip** section below. +::: + + +```js +const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config'); + +module.exports = function (baseConfig) { + const defaultConfig = mergeConfig(baseConfig, getDefaultConfig(__dirname)); + const {resolver: {assetExts, sourceExts}} = defaultConfig; + + return mergeConfig( + defaultConfig, + { + resolver: { + assetExts: assetExts.filter(ext => ext !== 'svg'), + sourceExts: [...sourceExts, 'svg'], + }, + }, + ); +}; +``` + +:::tip +Using a config function is for advanced use cases. A simpler method than the above, e.g. for customising `sourceExts`, would be to read these defaults from **@react-native/metro-config**. + +**Alternative** + + +```js +const defaultConfig = getDefaultConfig(__dirname); + +const config = { + resolver: { + sourceExts: [...defaultConfig.resolver.sourceExts, 'svg'], + }, +}; + +module.exports = mergeConfig(defaultConfig, config); +``` + +**However!**, we recommend copying and editing when overriding these config values — placing the source of truth in your config file. + +✅ **Recommended** + + +```js +const config = { + resolver: { + sourceExts: ['js', 'ts', 'tsx', 'svg'], + }, +}; +``` + +::: + +## Learn more about Metro + +- [Metro website](https://facebook.github.io/metro/) +- [Video: "Metro & React Native DevX" talk at App.js 2023](https://www.youtube.com/watch?v=c9D4pg0y9cI) diff --git a/docs/ram-bundles-inline-requires.md b/docs/ram-bundles-inline-requires.md index b7f5ba9e912..0a69c941ed5 100644 --- a/docs/ram-bundles-inline-requires.md +++ b/docs/ram-bundles-inline-requires.md @@ -148,21 +148,20 @@ Every app is different, but it may make sense to only load the modules you need We now need to update `metro.config.js` in the root of the project to use our newly generated `modulePaths.js` file: + ```js -const modulePaths = require('./packager/modulePaths'); -const resolve = require('path').resolve; +const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config'); const fs = require('fs'); - -// Update the following line if the root folder of your app is somewhere else. -const ROOT_FOLDER = resolve(__dirname, '..'); +const path = require('path'); +const modulePaths = require('./packager/modulePaths'); const config = { transformer: { getTransformOptions: () => { const moduleMap = {}; - modulePaths.forEach(path => { - if (fs.existsSync(path)) { - moduleMap[resolve(path)] = true; + modulePaths.forEach(modulePath => { + if (fs.existsSync(modulePath)) { + moduleMap[path.resolve(modulePath)] = true; } }); return { @@ -171,12 +170,13 @@ const config = { }; }, }, - projectRoot: ROOT_FOLDER, }; -module.exports = config; +module.exports = mergeConfig(getDefaultConfig(__dirname), config); ``` +See also [**Configuring Metro**](/docs/metro#configuring-metro). + The `preloadedModules` entry in the config indicates which modules should be marked as preloaded when building a RAM bundle. When the bundle is loaded, those modules are immediately loaded, before any requires have even executed. The `blockList` entry indicates that those modules should not be required inline. Because they are preloaded, there is no performance benefit from using an inline require. In fact the generated JavaScript spends extra time resolving the inline require every time the imports are referenced. ## Test and Measure Improvements diff --git a/website/sidebars.json b/website/sidebars.json index 6ab5547dda6..45cc7e83d10 100644 --- a/website/sidebars.json +++ b/website/sidebars.json @@ -21,6 +21,7 @@ "Workflow": [ "running-on-device", "fast-refresh", + "metro", { "type": "category", "label": "Debugging", diff --git a/website/versioned_docs/version-0.72/metro.md b/website/versioned_docs/version-0.72/metro.md new file mode 100644 index 00000000000..bf47d13ce54 --- /dev/null +++ b/website/versioned_docs/version-0.72/metro.md @@ -0,0 +1,104 @@ +--- +id: metro +title: Metro +--- + +React Native uses [Metro](https://facebook.github.io/metro/) to build your JavaScript code and assets. + +## Configuring Metro + +Configuration options for Metro can be customized in your project's `metro.config.js` file. This can export either: + +- **An object (recommended)** that will be merged on top of Metro's internal config defaults. +- [**A function**](#advanced-using-a-config-function) that will be called with Metro's internal config defaults and should return a final config object. + +:::tip +Please see [**Configuring Metro**](https://facebook.github.io/metro/docs/configuration) on the Metro website for documentation on all available config options. +::: + +In React Native, your Metro config should extend either [@react-native/metro-config](https://www.npmjs.com/package/@react-native/metro-config) or [@expo/metro-config](https://www.npmjs.com/package/@expo/metro-config). These packages contain essential defaults necessary to build and run React Native apps. + +Below is the default `metro.config.js` file in a React Native template project: + + +```js +const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config'); + +/** + * Metro configuration + * https://facebook.github.io/metro/docs/configuration + * + * @type {import('metro-config').MetroConfig} + */ +const config = {}; + +module.exports = mergeConfig(getDefaultConfig(__dirname), config); +``` + +Metro options you wish to customize can be done so within the `config` object. We strongly recommend defining all config values statically within this file. + +### Advanced: Using a config function + +Exporting a config function is an opt-in to managing the final config yourself — **Metro will not apply any internal defaults**. This pattern can be useful when needing to read the base default config object from Metro or to set options dynamically. + +:::info +**From @react-native/metro-config `0.72.1`**, it is no longer necessary to use a config function to access the complete default config. See the **Tip** section below. +::: + + +```js +const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config'); + +module.exports = function (baseConfig) { + const defaultConfig = mergeConfig(baseConfig, getDefaultConfig(__dirname)); + const {resolver: {assetExts, sourceExts}} = defaultConfig; + + return mergeConfig( + defaultConfig, + { + resolver: { + assetExts: assetExts.filter(ext => ext !== 'svg'), + sourceExts: [...sourceExts, 'svg'], + }, + }, + ); +}; +``` + +:::tip +Using a config function is for advanced use cases. A simpler method than the above, e.g. for customising `sourceExts`, would be to read these defaults from **@react-native/metro-config**. + +**Alternative** + + +```js +const defaultConfig = getDefaultConfig(__dirname); + +const config = { + resolver: { + sourceExts: [...defaultConfig.resolver.sourceExts, 'svg'], + }, +}; + +module.exports = mergeConfig(defaultConfig, config); +``` + +**However!**, we recommend copying and editing when overriding these config values — placing the source of truth in your config file. + +✅ **Recommended** + + +```js +const config = { + resolver: { + sourceExts: ['js', 'ts', 'tsx', 'svg'], + }, +}; +``` + +::: + +## Learn more about Metro + +- [Metro website](https://facebook.github.io/metro/) +- [Video: "Metro & React Native DevX" talk at App.js 2023](https://www.youtube.com/watch?v=c9D4pg0y9cI) diff --git a/website/versioned_docs/version-0.72/ram-bundles-inline-requires.md b/website/versioned_docs/version-0.72/ram-bundles-inline-requires.md index b7f5ba9e912..0a69c941ed5 100644 --- a/website/versioned_docs/version-0.72/ram-bundles-inline-requires.md +++ b/website/versioned_docs/version-0.72/ram-bundles-inline-requires.md @@ -148,21 +148,20 @@ Every app is different, but it may make sense to only load the modules you need We now need to update `metro.config.js` in the root of the project to use our newly generated `modulePaths.js` file: + ```js -const modulePaths = require('./packager/modulePaths'); -const resolve = require('path').resolve; +const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config'); const fs = require('fs'); - -// Update the following line if the root folder of your app is somewhere else. -const ROOT_FOLDER = resolve(__dirname, '..'); +const path = require('path'); +const modulePaths = require('./packager/modulePaths'); const config = { transformer: { getTransformOptions: () => { const moduleMap = {}; - modulePaths.forEach(path => { - if (fs.existsSync(path)) { - moduleMap[resolve(path)] = true; + modulePaths.forEach(modulePath => { + if (fs.existsSync(modulePath)) { + moduleMap[path.resolve(modulePath)] = true; } }); return { @@ -171,12 +170,13 @@ const config = { }; }, }, - projectRoot: ROOT_FOLDER, }; -module.exports = config; +module.exports = mergeConfig(getDefaultConfig(__dirname), config); ``` +See also [**Configuring Metro**](/docs/metro#configuring-metro). + The `preloadedModules` entry in the config indicates which modules should be marked as preloaded when building a RAM bundle. When the bundle is loaded, those modules are immediately loaded, before any requires have even executed. The `blockList` entry indicates that those modules should not be required inline. Because they are preloaded, there is no performance benefit from using an inline require. In fact the generated JavaScript spends extra time resolving the inline require every time the imports are referenced. ## Test and Measure Improvements diff --git a/website/versioned_sidebars/version-0.72-sidebars.json b/website/versioned_sidebars/version-0.72-sidebars.json index 6ab5547dda6..45cc7e83d10 100644 --- a/website/versioned_sidebars/version-0.72-sidebars.json +++ b/website/versioned_sidebars/version-0.72-sidebars.json @@ -21,6 +21,7 @@ "Workflow": [ "running-on-device", "fast-refresh", + "metro", { "type": "category", "label": "Debugging",