Files
react-native/packages/debugger-shell/src/electron/MainInstanceEntryPoint.js
T
Moti Zilberman bf51035e04 Scaffolding for custom RNDT shell binary (#52357)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/52357

Changelog: [Internal]

Adds a hyper-minimal build script using `electron/packager` that produces custom binaries for the experimental React Native DevTools standalone shell. The main user-facing benefit of this is replacing the Electron name and icon with our own branding.

NOTE: `electron/packager` is designed to include the application code in the resulting binary. This is arguably overkill for us - the current launch model of `electron src/electron/index.js` is actually wholly sufficient for what we need - but I decided to go with the grain of the available tooling for simplicity.

Icon design courtesy of huntie. 🙏

Reviewed By: huntie

Differential Revision: D77591742

fbshipit-source-id: a968465df4f54fba54c874b6300788e151600ed7
2025-07-02 03:48:51 -07:00

122 lines
2.7 KiB
JavaScript

/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
*/
// $FlowFixMe[unclear-type] We have no Flow types for the Electron API.
const {BrowserWindow, app, shell, ipcMain} = require('electron') as any;
const path = require('path');
const util = require('util');
const windowMetadata = new WeakMap<
typeof BrowserWindow,
$ReadOnly<{
windowKey: string,
}>,
>();
function handleLaunchArgs(argv: string[]) {
const {
values: {frontendUrl, windowKey},
} = util.parseArgs({
options: {
frontendUrl: {
type: 'string',
},
windowKey: {
type: 'string',
},
},
args: argv,
});
// Find an existing window for this app and launch configuration.
const existingWindow = BrowserWindow.getAllWindows().find(window => {
const metadata = windowMetadata.get(window);
if (!metadata) {
return false;
}
return metadata.windowKey === windowKey;
});
if (existingWindow) {
// If the window is already visible, flash it.
if (existingWindow.isVisible()) {
existingWindow.flashFrame(true);
setTimeout(() => {
existingWindow.flashFrame(false);
}, 1000);
}
if (process.platform === 'darwin') {
app.focus({
steal: true,
});
}
existingWindow.focus();
return;
}
// 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'};
});
frontendWindow.loadURL(frontendUrl);
windowMetadata.set(frontendWindow, {
windowKey,
});
if (process.platform === 'darwin') {
app.focus({
steal: true,
});
}
}
app.whenReady().then(() => {
handleLaunchArgs(process.argv.slice(app.isPackaged ? 1 : 2));
app.on(
'second-instance',
(event, electronArgv, workingDirectory, additionalData) => {
handleLaunchArgs(additionalData.argv);
},
);
});
app.on('window-all-closed', function () {
app.quit();
});
ipcMain.on('bringToFront', (event, title) => {
const webContents = event.sender;
const win = BrowserWindow.fromWebContents(webContents);
if (win) {
win.focus();
}
if (process.platform === 'darwin') {
app.focus({
steal: true,
});
}
});