From ca92b8f043f85da9842c1dcce73270ebe53757c0 Mon Sep 17 00:00:00 2001 From: Rob Hogan Date: Mon, 13 Jul 2026 06:46:51 -0700 Subject: [PATCH] Enable `allowOptionalDependencies` by default (#1775) Summary: Flip the default value of the `transformer.allowOptionalDependencies` Metro config option from `false` to `true` in `metro-config`'s own defaults. This allows for patterns like: ```js let dep = null; try { // If not installed, allowOptionalDependencies === // true => throw at runtime, handled by catch // false => throw at build time dep = require('maybe-installed-dependency'); } catch { dep = require('./my-fallback'); } ``` Which comes up in popular packages, eg [`lru-cache`](https://github.com/isaacs/node-lru-cache/blob/16b3a916662ab449d496b7b4b4f04132565d1d28/src/diagnostics-channel-esm.mts#L24-L29). Note that this is *already the default* in: - `react-native/metro-config`: https://github.com/react/react-native/blob/a632f9efe24bac8b3a113c78469948f55bde0f5d/packages/metro-config/src/index.flow.js#L86 - And `expo/metro-config`: https://github.com/expo/expo/blob/ab042edb8228e3873bdbd8e04b7c61cd3e00372e/packages/%40expo/metro-config/src/ExpoMetroConfig.ts#L423 There were previously known problems with `allowOptionalDependencies` and the behaviour of subsequently declared dependencies, and they were also broken under HMR if their existence changed. These were both fixed a year ago in https://github.com/react/metro/pull/1522. The heuristic was also quite limited, for example a `try { require() }` was considered optional but an `import().catch()` was not. That was fixed in https://github.com/react/metro/pull/1697. I can't think of any good reason not to enable this and fix the misalignment with RN/Expo. With this enabled, dependencies referenced inside `try/catch` blocks (and dynamic `import()`s with rejection handlers) are treated as optional by default: an unresolvable optional dependency no longer fails the build, matching the common expectation for guarded requires. Projects can still opt out by explicitly setting `allowOptionalDependencies: false`. Since this change doesn't alter observable runtime behaviour (it allows bundles to build that would otherwise fail to build), I'm inclined to regard it as non-breaking. ``` - **[Feature]**: `allowOptionalDependencies` defaults to `true` to align with RN and Expo ``` Reviewed By: huntie Differential Revision: D111577052 --- packages/metro-config/src/defaults/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/metro-config/src/defaults/index.js b/packages/metro-config/src/defaults/index.js index 2d7df87df2..681b8f317b 100644 --- a/packages/metro-config/src/defaults/index.js +++ b/packages/metro-config/src/defaults/index.js @@ -128,7 +128,7 @@ const getDefaultValues = (projectRoot: ?string): ConfigT => ({ optimizationSizeLimit: 150 * 1024, // 150 KiB. transformVariants: {default: {}}, publicPath: '/assets', - allowOptionalDependencies: false, + allowOptionalDependencies: true, unstable_allowRequireContext: false, unstable_dependencyMapReservedName: null, unstable_disableModuleWrapping: false,