From f2cd681a2ce8be6c27a8aa64d01c43ab5a8fc606 Mon Sep 17 00:00:00 2001 From: Riccardo Cipolleschi Date: Thu, 9 Jul 2026 04:54:28 -0700 Subject: [PATCH 1/2] Keep react-native/setup-env reachable in the module graph (#57492) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: https://github.com/react/react-native/issues/57475 pointed Metro's `getModulesRunBeforeMainModule` at `react-native/setup-env` (`src/setup-env.js`) instead of `InitializeCore`. But Metro's serializer only emits a run-before-main require for modules **already in the bundle graph** — see `getAppendScripts`: ```js const paths = [...options.runBeforeMainModule, entryPoint]; for (const path of paths) { if (modules.some(module => module.path === path)) { /* emit run stmt */ } } ``` Nothing imports `src/setup-env.js` at runtime, so it was silently dropped. The RN environment setup (`setUpDefaultReactNativeEnvironment`: `HMRClient`, timers, batched bridge, `AppRegistry` setup, …) then never ran before the app's main module, and the app **redboxed on launch**: ``` Error: Failed to call into JavaScript module method HMRClient.setup(). Module has not been registered as callable. Registered callable JavaScript modules (n = 1): AppRegistry. ``` This broke the **template E2E tests** on both iOS and Android — the app renders a redbox, so Maestro's `assertVisible: 'Welcome to React Native'` fails (the `test (…)` jobs are green only because the Maestro step runs with `continue-on-error: true`; the real failure surfaces via the retry chain and the `retry_2 / report` job). ## Fix Have the deprecated `InitializeCore` delegate to `'react-native/setup-env'` via a side-effectful `require`. `InitializeCore` is a guaranteed graph entry (renderer → `ReactNativePrivateInitializeCore` → `InitializeCore`), so this pulls `src/setup-env.js` into the graph, and `getModulesRunBeforeMainModule` runs it before the main module again. Behavior is unchanged: `setup-env` and `InitializeCore` both call the idempotent `setUpDefaultReactNativeEnvironment()`. This keeps https://github.com/react/react-native/issues/57475's move to `setup-env` intact rather than reverting it. ## Changelog: [General][Fixed] - Fix app failing to initialize (`HMRClient.setup()` redbox) because the environment setup module was dropped from the bundle Pull Request resolved: https://github.com/react/react-native/pull/57492 Test Plan: - Template E2E (`test_e2e_ios_templateapp` / `test_e2e_android_templateapp`) should pass: app launches and shows "Welcome to React Native" instead of the redbox. cc huntie (https://github.com/react/react-native/issues/57475) Reviewed By: cipolleschi Differential Revision: D111226610 Pulled By: huntie fbshipit-source-id: b44e82a248c1f2333c2ea85001c9f243b54619ad --- packages/react-native/Libraries/Core/InitializeCore.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/react-native/Libraries/Core/InitializeCore.js b/packages/react-native/Libraries/Core/InitializeCore.js index 8846ce4dea5..a53aedfe899 100644 --- a/packages/react-native/Libraries/Core/InitializeCore.js +++ b/packages/react-native/Libraries/Core/InitializeCore.js @@ -27,4 +27,11 @@ 'use strict'; -require('../../src/private/setup/setUpDefaultReactNativeEnvironment').default(); +// NOTE: This delegates to the `'react-native/setup-env'` entry point (rather +// than calling `setUpDefaultReactNativeEnvironment` directly) so that +// `src/setup-env.js` is pulled into the module graph. Metro's +// `getModulesRunBeforeMainModule` only runs modules that are already part of +// the bundle, and `InitializeCore` is a guaranteed graph entry (via +// `ReactNativePrivateInitializeCore`). This keeps `'react-native/setup-env'` +// reachable so it runs before the main module. +require('../../src/setup-env'); From 8d727cca68a3c022e14a28cb11749edc3e613137 Mon Sep 17 00:00:00 2001 From: Alex Hunt Date: Wed, 15 Jul 2026 11:23:22 +0100 Subject: [PATCH 2/2] [LOCAL] Restore newer setup-env import in Metro configs This reverts commit 9b76007ae0cc2837d9f9ad68e4340df95d5e42a6. --- packages/community-cli-plugin/src/utils/loadMetroConfig.js | 6 +++--- packages/metro-config/src/index.flow.js | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/community-cli-plugin/src/utils/loadMetroConfig.js b/packages/community-cli-plugin/src/utils/loadMetroConfig.js index 7e2f5c3d002..9b6a79ee104 100644 --- a/packages/community-cli-plugin/src/utils/loadMetroConfig.js +++ b/packages/community-cli-plugin/src/utils/loadMetroConfig.js @@ -58,15 +58,15 @@ function getCommunityCliDefaultConfig( return { resolver, serializer: { - // We can include multiple copies of InitializeCore here because metro will + // We can include multiple copies of setup-env here because Metro will // only add ones that are already part of the bundle getModulesRunBeforeMainModule: () => [ - require.resolve('react-native/Libraries/Core/InitializeCore', { + require.resolve('react-native/setup-env', { paths: [ctx.root], }), ...outOfTreePlatforms.map(platform => require.resolve( - `${ctx.platforms[platform].npmPackageName}/Libraries/Core/InitializeCore`, + `${ctx.platforms[platform].npmPackageName}/setup-env`, {paths: [ctx.root]}, ), ), diff --git a/packages/metro-config/src/index.flow.js b/packages/metro-config/src/index.flow.js index 1988c902ed3..74fc4053c2b 100644 --- a/packages/metro-config/src/index.flow.js +++ b/packages/metro-config/src/index.flow.js @@ -61,7 +61,7 @@ export function getDefaultConfig(projectRoot: string): ConfigT { serializer: { // NOTE: Overridden in community-cli-plugin getModulesRunBeforeMainModule: () => [ - require.resolve('react-native/Libraries/Core/InitializeCore'), + require.resolve('react-native/setup-env'), ], getPolyfills: () => require('@react-native/js-polyfills')(), isThirdPartyModule({path: modulePath}: Readonly<{path: string, ...}>) {