diff --git a/packages/debugger-shell/src/node/index.flow.js b/packages/debugger-shell/src/node/index.flow.js index 7c4e06831c5036..476cf33656bc15 100644 --- a/packages/debugger-shell/src/node/index.flow.js +++ b/packages/debugger-shell/src/node/index.flow.js @@ -29,7 +29,7 @@ async function unstable_spawnDebuggerShellWithArgs( args: string[], { mode = 'detached', - flavor = 'prebuilt', + flavor = process.env.RNDT_DEV === '1' ? 'dev' : 'prebuilt', prebuiltBinaryPath, }: $ReadOnly<{ // In 'syncAndExit' mode, the current process will block until the spawned process exits, and then it will exit @@ -38,7 +38,7 @@ async function unstable_spawnDebuggerShellWithArgs( // continue to run normally. mode?: 'syncThenExit' | 'detached', flavor?: DebuggerShellFlavor, - prebuiltBinaryPath?: string, + prebuiltBinaryPath?: ?string, }> = {}, ): Promise { const [binaryPath, baseArgs] = getShellBinaryAndArgs( @@ -51,6 +51,13 @@ async function unstable_spawnDebuggerShellWithArgs( stdio: 'inherit', windowsHide: true, detached: mode === 'detached', + env: { + ...process.env, + // If this package is used in an Electron app (e.g. inside a VS Code extension), + // ELECTRON_RUN_AS_NODE=1 can leak from the parent process. + // Since this is never the right way to launch the Fusebox shell, we guard against it here. + ELECTRON_RUN_AS_NODE: '', + }, }); if (mode === 'detached') { child.on('spawn', () => { @@ -112,10 +119,13 @@ export type DebuggerShellPreparationResult = $ReadOnly<{ * instantly when the user tries to open it (and conversely, the user is * informed ASAP if it is not ready to use). */ -async function unstable_prepareDebuggerShell( - flavor: DebuggerShellFlavor, - {prebuiltBinaryPath}: {prebuiltBinaryPath?: string} = {}, -): Promise { +async function unstable_prepareDebuggerShell({ + prebuiltBinaryPath, + flavor = process.env.RNDT_DEV === '1' ? 'dev' : 'prebuilt', +}: { + prebuiltBinaryPath?: ?string, + flavor?: DebuggerShellFlavor, +} = {}): Promise { try { switch (flavor) { case 'prebuilt': diff --git a/packages/dev-middleware/src/createDevMiddleware.js b/packages/dev-middleware/src/createDevMiddleware.js index 72d1bdd52de000..9afc7c1aa12690 100644 --- a/packages/dev-middleware/src/createDevMiddleware.js +++ b/packages/dev-middleware/src/createDevMiddleware.js @@ -9,6 +9,7 @@ */ import type {CreateCustomMessageHandlerFn} from './inspector-proxy/CustomMessageHandler'; +import type {HasConnectedDevicesListener} from './inspector-proxy/InspectorProxy'; import type {BrowserLauncher} from './types/BrowserLauncher'; import type {EventReporter, ReportableEvent} from './types/EventReporter'; import type {Experiments, ExperimentsConfig} from './types/Experiments'; @@ -73,6 +74,8 @@ type Options = $ReadOnly<{ type DevMiddlewareAPI = $ReadOnly<{ middleware: NextHandleFunction, websocketEndpoints: {[path: string]: ws$WebSocketServer}, + unstable_hasConnectedDevices(): boolean, + unstable_addHasConnectedDevicesListener: HasConnectedDevicesListener, }>; export default function createDevMiddleware({ @@ -131,6 +134,10 @@ export default function createDevMiddleware({ return { middleware, websocketEndpoints: inspectorProxy.createWebSocketListeners(), + unstable_hasConnectedDevices: () => + inspectorProxy.unstable_hasConnectedDevices(), + unstable_addHasConnectedDevicesListener: cb => + inspectorProxy.unstable_addHasConnectedDevicesListener(cb), }; } diff --git a/packages/dev-middleware/src/inspector-proxy/InspectorProxy.js b/packages/dev-middleware/src/inspector-proxy/InspectorProxy.js index f9f419b1124d75..77343a19b458d9 100644 --- a/packages/dev-middleware/src/inspector-proxy/InspectorProxy.js +++ b/packages/dev-middleware/src/inspector-proxy/InspectorProxy.js @@ -71,6 +71,12 @@ export interface InspectorProxyQueries { ): Array; } +export type RemoveHasConnectedDevicesListener = () => void; + +export type HasConnectedDevicesListener = ( + callback: (hasConnectedDevices: boolean) => void, +) => RemoveHasConnectedDevicesListener; + /** * Main Inspector Proxy class that connects JavaScript VM inside Android/iOS apps and JS debugger. */ @@ -97,6 +103,8 @@ export default class InspectorProxy implements InspectorProxyQueries { #eventLoopPerfTracker: EventLoopPerfTracker; + #onHasConnectedDevicesChangedFns: Set<(boolean) => void>; + constructor( serverBaseUrl: string, eventReporter: ?EventReporter, @@ -111,6 +119,7 @@ export default class InspectorProxy implements InspectorProxyQueries { this.#experiments = experiments; this.#logger = logger; this.#customMessageHandler = customMessageHandler; + this.#onHasConnectedDevicesChangedFns = new Set(); if (trackEventLoopPerf) { this.#eventLoopPerfTracker = new EventLoopPerfTracker({ perfMeasurementDuration: EVENT_LOOP_PERF_MEASUREMENT_MS, @@ -142,6 +151,18 @@ export default class InspectorProxy implements InspectorProxyQueries { } } + unstable_hasConnectedDevices(): boolean { + return this.#devices.size > 0; + } + + unstable_addHasConnectedDevicesListener: HasConnectedDevicesListener = + onDevicesChanged => { + this.#onHasConnectedDevicesChangedFns.add(onDevicesChanged); + return () => { + this.#onHasConnectedDevicesChangedFns.delete(onDevicesChanged); + }; + }; + getPageDescriptions({ requestorRelativeBaseUrl, logNoPagesForConnectedDevice = false, @@ -365,6 +386,9 @@ export default class InspectorProxy implements InspectorProxyQueries { } this.#devices.set(deviceId, newDevice); + if (this.#devices.size === 1) { + this.#onHasConnectedDevicesChangedFns.forEach(cb => cb(true)); + } debug( "Got new device connection: name='%s', app=%s, device=%s, via=%s", @@ -457,6 +481,9 @@ export default class InspectorProxy implements InspectorProxyQueries { if (this.#devices.get(deviceId)?.dangerouslyGetSocket() === socket) { this.#devices.delete(deviceId); + if (this.#devices.size === 0) { + this.#onHasConnectedDevicesChangedFns.forEach(cb => cb(false)); + } } }); } catch (error) { diff --git a/packages/dev-middleware/src/utils/DefaultBrowserLauncher.js b/packages/dev-middleware/src/utils/DefaultBrowserLauncher.js index dfe393c409f1b9..ee43ddb48d7e11 100644 --- a/packages/dev-middleware/src/utils/DefaultBrowserLauncher.js +++ b/packages/dev-middleware/src/utils/DefaultBrowserLauncher.js @@ -73,19 +73,16 @@ const DefaultBrowserLauncher = { url: string, windowKey: string, ): Promise { - return await unstable_spawnDebuggerShellWithArgs( - ['--frontendUrl=' + url, '--windowKey=' + windowKey], - { - mode: 'detached', - flavor: process.env.RNDT_DEV === '1' ? 'dev' : 'prebuilt', - }, - ); + return await unstable_spawnDebuggerShellWithArgs([ + '--frontendUrl=' + url, + '--windowKey=' + windowKey, + ]); }, - async unstable_prepareFuseboxShell(): Promise { - return await unstable_prepareDebuggerShell( - process.env.RNDT_DEV === '1' ? 'dev' : 'prebuilt', - ); + async unstable_prepareFuseboxShell( + prebuiltBinaryPath?: ?string, + ): Promise { + return await unstable_prepareDebuggerShell(); }, };