From 1483f9eec0a1c104eb8aa85282121f7aa371d05a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20Norte?= Date: Tue, 12 Aug 2025 03:40:34 -0700 Subject: [PATCH 1/3] Refactor logic to find available port for Metro in Fantom (#53204) Summary: Changelog: [internal] This changes the logic to find an available port for Metro on Fantom to do this outside Metro. Before, we'd set `0` as the port for Metro to find an available port, but in a following change we'll need to know the port before calling into Metro. This allows that. Reviewed By: rshest Differential Revision: D79804005 --- .../runner/global-setup/globalSetup.js | 35 +++++++++++++------ 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/private/react-native-fantom/runner/global-setup/globalSetup.js b/private/react-native-fantom/runner/global-setup/globalSetup.js index f87eec9848a0..af8871e74d97 100644 --- a/private/react-native-fantom/runner/global-setup/globalSetup.js +++ b/private/react-native-fantom/runner/global-setup/globalSetup.js @@ -11,6 +11,7 @@ import {isOSS, validateEnvironmentVariables} from '../EnvironmentOptions'; import build from './build'; import Metro from 'metro'; +import {Server} from 'net'; import path from 'path'; export default async function globalSetup( @@ -33,26 +34,38 @@ async function startMetroServer() { config: path.resolve(__dirname, '..', '..', 'config', 'metro.config.js'), }); + if (process.env.__FANTOM_METRO_PORT__ == null) { + const availablePort = await findAvailablePort(); + process.env.__FANTOM_METRO_PORT__ = String(availablePort); + } + // We need to reuse the same port across runs because can only set environment // variables for workers in the first one. // $FlowExpectedError[cannot-write] - metroConfig.server.port = - process.env.__FANTOM_METRO_PORT__ != null - ? Number(process.env.__FANTOM_METRO_PORT__) - : // Any available port - 0; + metroConfig.server.port = Number(process.env.__FANTOM_METRO_PORT__); const server = await Metro.runServer(metroConfig, { waitForBundler: true, watch: true, }); - if (process.env.__FANTOM_METRO_PORT__ == null) { - process.env.__FANTOM_METRO_PORT__ = String( - server.httpServer.address().port, - ); - } - // $FlowExpectedError[prop-missing] globalThis.__METRO_SERVER__ = server; } + +async function findAvailablePort(): Promise { + return new Promise((resolve, reject) => { + const server = new Server(); + server.listen(0, 'localhost', undefined, () => { + const port = server.address().port; + server.close(error => { + if (error != null) { + reject(error); + } else { + resolve(port); + } + }); + }); + server.on('error', reject); + }); +} From bdf6a602239fc936890c1079733aed468d92900e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20Norte?= Date: Tue, 12 Aug 2025 03:40:34 -0700 Subject: [PATCH 2/3] Rename global variable with Metro server for Fantom (#53202) Summary: Changelog: [internal] Just a minor refactor to follow the convention of prefixing Fantom-related globals and environment variables. Reviewed By: rshest Differential Revision: D79804007 --- .../react-native-fantom/runner/global-setup/globalSetup.js | 2 +- .../runner/global-setup/globalTeardown.js | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/private/react-native-fantom/runner/global-setup/globalSetup.js b/private/react-native-fantom/runner/global-setup/globalSetup.js index af8871e74d97..94bf690a0335 100644 --- a/private/react-native-fantom/runner/global-setup/globalSetup.js +++ b/private/react-native-fantom/runner/global-setup/globalSetup.js @@ -50,7 +50,7 @@ async function startMetroServer() { }); // $FlowExpectedError[prop-missing] - globalThis.__METRO_SERVER__ = server; + globalThis.__FANTOM_METRO_SERVER__ = server; } async function findAvailablePort(): Promise { diff --git a/private/react-native-fantom/runner/global-setup/globalTeardown.js b/private/react-native-fantom/runner/global-setup/globalTeardown.js index 477bd3202389..1f6c4bd63e50 100644 --- a/private/react-native-fantom/runner/global-setup/globalTeardown.js +++ b/private/react-native-fantom/runner/global-setup/globalTeardown.js @@ -12,11 +12,12 @@ import type {RunServerResult} from 'metro'; type MetroServer = $NonMaybeType; -declare var __METRO_SERVER__: ?RunServerResult; +declare var __FANTOM_METRO_SERVER__: ?RunServerResult; function getMetroServer(): ?MetroServer { - return typeof __METRO_SERVER__ !== 'undefined' && __METRO_SERVER__ != null - ? __METRO_SERVER__.httpServer + return typeof __FANTOM_METRO_SERVER__ !== 'undefined' && + __FANTOM_METRO_SERVER__ != null + ? __FANTOM_METRO_SERVER__.httpServer : null; } From 1c662a89485f1d5203464b9003a9f31a01c9261a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20Norte?= Date: Tue, 12 Aug 2025 03:40:34 -0700 Subject: [PATCH 3/3] Connect debugger before loading bundle (#53203) Summary: Changelog: [internal] This makes ReactHost connect the inspector immediately after creating the instance, aligned with how we do it on Android, instead of doing it as part of loading a bundle. Reviewed By: rshest Differential Revision: D79804004 --- .../ReactCxxPlatform/react/runtime/ReactHost.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/react-native/ReactCxxPlatform/react/runtime/ReactHost.cpp b/packages/react-native/ReactCxxPlatform/react/runtime/ReactHost.cpp index bcd8d15f8aed..b53b2b83bcfd 100644 --- a/packages/react-native/ReactCxxPlatform/react/runtime/ReactHost.cpp +++ b/packages/react-native/ReactCxxPlatform/react/runtime/ReactHost.cpp @@ -240,6 +240,10 @@ void ReactHost::createReactInstance() { auto jsInvoker = std::make_shared( reactInstance_->getRuntimeScheduler()); + if (inspector_ != nullptr) { + inspector_->connectDebugger(devServerHelper_->getInspectorUrl()); + } + auto liveReloadCallback = [this]() { reloadReactInstance(); }; reactInstance_->initializeRuntime( { @@ -451,9 +455,6 @@ bool ReactHost::loadScriptFromDevServer() { auto script = std::make_unique(response); reactInstance_->loadScript( std::move(script), devServerHelper_->getBundleUrl()); - if (inspector_ != nullptr) { - inspector_->connectDebugger(devServerHelper_->getInspectorUrl()); - } devServerHelper_->setupHMRClient(); return true; } catch (...) {