From 33be0606c1912b90e6e2c93fc8c90de0692478c2 Mon Sep 17 00:00:00 2001 From: Moti Zilberman Date: Fri, 22 Aug 2025 04:03:08 -0700 Subject: [PATCH] Always reload the frontend when launching, even in an existing window (#53407) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/53407 Changelog: [Internal] ## Context Upon receiving a launch command, the RNDT shell either: 1. Creates a new window and navigates to the requested frontend URL. 2. Brings an existing window to the foreground *with no further navigation*. In the happy path, (2) is a pretty nice experience: it preserves all prior UI state in the frontend and leaves the user with an instantly responsive debugger - this can be quite a bit faster than (1) because of the overhead of loading and parsing source maps for example. However, this breaks down if the frontend is not in a usable state to begin with. This is, sadly, a frequent-enough occurrence that we must account for it: the CDP connection may have been lost, the frontend app itself might have failed to load the last time, etc. Preserving everything that's nice about (2) while also making it fully reliable - incrementally bringing the frontend to the state specified by a new URL - would require delicate engineering across the shell and frontend codebases, which is an amount of complexity I would like to sidestep for now. NOTE: The more complex solution **is 100% worth implementing in the long term,** as it has tangible benefits for the user, and matches Chrome best. ## This diff Here we take a much cheaper approach than the one described above: the shell will *always* initiate navigation to the new frontend URL, regardless of whether it does so in a new window or a previously opened one. This will consistently bring the user to a state where the frontend is open and working (although it will reset any ephemeral UI state in the process, and typically take a noticeable amount of time to load). Even with this simplified approach, the standalone shell still offers a better experience than launching in a browser (if only because it is zero-install and avoids the "dead tab spam" problem). Reviewed By: huntie Differential Revision: D80711185 fbshipit-source-id: 8f376ccf1717c48a1742c798da3171ac6d2f8af0 --- .../src/electron/MainInstanceEntryPoint.js | 45 +++++++++---------- 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/packages/debugger-shell/src/electron/MainInstanceEntryPoint.js b/packages/debugger-shell/src/electron/MainInstanceEntryPoint.js index 45c7326d0f7..3434787d5f6 100644 --- a/packages/debugger-shell/src/electron/MainInstanceEntryPoint.js +++ b/packages/debugger-shell/src/electron/MainInstanceEntryPoint.js @@ -36,7 +36,7 @@ function handleLaunchArgs(argv: string[]) { }); // Find an existing window for this app and launch configuration. - const existingWindow = BrowserWindow.getAllWindows().find(window => { + let frontendWindow = BrowserWindow.getAllWindows().find(window => { const metadata = windowMetadata.get(window); if (!metadata) { return false; @@ -44,41 +44,37 @@ function handleLaunchArgs(argv: string[]) { return metadata.windowKey === windowKey; }); - if (existingWindow) { + if (frontendWindow) { // If the window is already visible, flash it. - if (existingWindow.isVisible()) { - existingWindow.flashFrame(true); + if (frontendWindow.isVisible()) { + frontendWindow.flashFrame(true); setTimeout(() => { - existingWindow.flashFrame(false); + frontendWindow.flashFrame(false); }, 1000); } - if (process.platform === 'darwin') { - app.focus({ - steal: true, - }); - } - existingWindow.focus(); - return; + } else { + // Create the browser window. + frontendWindow = new BrowserWindow({ + width: 1200, + height: 600, + webPreferences: { + partition: 'persist:react-native-devtools', + preload: require.resolve('./preload.js'), + }, + // Icon for Linux + icon: path.join(__dirname, 'resources', 'icon.png'), + }); } - // Create the browser window. - const frontendWindow = new BrowserWindow({ - width: 1200, - height: 600, - webPreferences: { - partition: 'persist:react-native-devtools', - preload: require.resolve('./preload.js'), - }, - // Icon for Linux - icon: path.join(__dirname, 'resources', 'icon.png'), - }); - // Open links in the default browser instead of in new Electron windows. frontendWindow.webContents.setWindowOpenHandler(({url}) => { shell.openExternal(url); return {action: 'deny'}; }); + // TODO: If the window contains a live, working frontend instance with a valid connection to the backend, + // we should avoid this reload and instead send the frontend a message to handle the launch arguments + // dynamically (e.g. update the launch ID for telemetry purposes, handle deeplinking to a specific CDT panel, etc). frontendWindow.loadURL(frontendUrl); windowMetadata.set(frontendWindow, { @@ -90,6 +86,7 @@ function handleLaunchArgs(argv: string[]) { steal: true, }); } + frontendWindow.focus(); } app.whenReady().then(() => {