From a9007ea586f6e87db47c6305be3232d760abfd57 Mon Sep 17 00:00:00 2001 From: Jakub Romanczyk Date: Fri, 6 Jun 2025 02:54:04 -0700 Subject: [PATCH] feat: process HMR `registerBundle` calls from same origin only (#51821) Summary: Part of https://github.com/facebook/metro/issues/1480 This PR adds a check in `HMRClient.js` that prevents processing `registerBundle` calls coming from different origin than the one declared in HMR `setup()`. This is useful in a Module Federation setup, where we have multiple HMRClients present in runtime - when Host loads external remote, the requestURL will have different origin, but it will be processed by the HMRClient from the Host which in turn causes a runtime error. ## Changelog: [GENERAL] [ADDED] - Process HMR registerBundle calls from the same origin only Pull Request resolved: https://github.com/facebook/react-native/pull/51821 Test Plan: TBD Reviewed By: christophpurrer Differential Revision: D76044353 Pulled By: huntie fbshipit-source-id: 3928347b1e9a90355d02b87b07fde812479bcb67 --- .../react-native/Libraries/Utilities/HMRClient.js | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/packages/react-native/Libraries/Utilities/HMRClient.js b/packages/react-native/Libraries/Utilities/HMRClient.js index c15cb4eff75..1f67f3e9b9d 100644 --- a/packages/react-native/Libraries/Utilities/HMRClient.js +++ b/packages/react-native/Libraries/Utilities/HMRClient.js @@ -23,6 +23,7 @@ const prettyFormat = require('pretty-format'); const pendingEntryPoints = []; let hmrClient = null; let hmrUnavailableReason: string | null = null; +let hmrOrigin: string | null = null; let currentCompileErrorMessage: string | null = null; let didConnect: boolean = false; let pendingLogs: Array<[LogLevel, $ReadOnlyArray]> = []; @@ -100,7 +101,14 @@ const HMRClient: HMRClientNativeInterface = { }, registerBundle(requestUrl: string) { - invariant(hmrClient, 'Expected HMRClient.setup() call at startup.'); + invariant( + hmrOrigin != null && hmrClient != null, + 'Expected HMRClient.setup() call at startup.', + ); + // only process registerBundle calls from the same origin + if (!requestUrl.startsWith(hmrOrigin)) { + return; + } pendingEntryPoints.push(requestUrl); registerBundleEntryPoints(hmrClient); }, @@ -162,8 +170,10 @@ const HMRClient: HMRClientNativeInterface = { const serverScheme = scheme; - const client = new MetroHMRClient(`${serverScheme}://${serverHost}/hot`); + const origin = `${serverScheme}://${serverHost}`; + const client = new MetroHMRClient(`${origin}/hot`); + hmrOrigin = origin; hmrClient = client; const {fullBundleUrl} = getDevServer();