diff --git a/flow-typed/npm/chrome-launcher_v0.15.x.js b/flow-typed/npm/chrome-launcher_v0.15.x.js deleted file mode 100644 index 4f7a3fef11a2..000000000000 --- a/flow-typed/npm/chrome-launcher_v0.15.x.js +++ /dev/null @@ -1,52 +0,0 @@ -/** - * 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 - * @format - */ - -declare module 'chrome-launcher' { - import typeof fs from 'fs'; - import typeof childProcess from 'child_process'; - import type {ChildProcess} from 'child_process'; - - declare export type Options = { - startingUrl?: string, - chromeFlags?: Array, - prefs?: unknown, - port?: number, - handleSIGINT?: boolean, - chromePath?: string, - userDataDir?: string | boolean, - logLevel?: 'verbose' | 'info' | 'error' | 'warn' | 'silent', - ignoreDefaultFlags?: boolean, - connectionPollInterval?: number, - maxConnectionRetries?: number, - envVars?: {[key: string]: ?string}, - }; - - declare export type LaunchedChrome = { - pid: number, - port: number, - process: ChildProcess, - kill: () => void, - }; - - declare export type ModuleOverrides = { - fs?: fs, - spawn?: childProcess['spawn'], - }; - - declare class Launcher { - getChromePath(): string; - launch(options: Options): Promise; - Launcher: { - defaultFlags(): Array, - }; - } - - declare module.exports: Launcher; -} diff --git a/flow-typed/npm/chromium-edge-launcher_v0.2.x.js b/flow-typed/npm/chromium-edge-launcher_v0.2.x.js deleted file mode 100644 index 0b74594465da..000000000000 --- a/flow-typed/npm/chromium-edge-launcher_v0.2.x.js +++ /dev/null @@ -1,52 +0,0 @@ -/** - * 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 - * @format - */ - -declare module 'chromium-edge-launcher' { - import typeof fs from 'fs'; - import typeof childProcess from 'child_process'; - import type {ChildProcess} from 'child_process'; - - declare export type Options = { - startingUrl?: string, - edgeFlags?: Array, - prefs?: unknown, - port?: number, - handleSIGINT?: boolean, - edgePath?: string, - userDataDir?: string | boolean, - logLevel?: 'verbose' | 'info' | 'error' | 'warn' | 'silent', - ignoreDefaultFlags?: boolean, - connectionPollInterval?: number, - maxConnectionRetries?: number, - envVars?: {[key: string]: ?string}, - }; - - declare export type LaunchedEdge = { - pid: number, - port: number, - process: ChildProcess, - kill: () => void, - }; - - declare export type ModuleOverrides = { - fs?: fs, - spawn?: childProcess['spawn'], - }; - - declare class Launcher { - getFirstInstallation(): string; - launch(options: Options): Promise; - } - - declare module.exports: { - default: Launcher, - Launcher: Launcher, - }; -} diff --git a/flow-typed/npm/open_v7.x.x.js b/flow-typed/npm/open_v7.x.x.js deleted file mode 100644 index 25f62fae2179..000000000000 --- a/flow-typed/npm/open_v7.x.x.js +++ /dev/null @@ -1,28 +0,0 @@ -/** - * 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 - * @format - */ - -declare module 'open' { - import type {ChildProcess} from 'child_process'; - - declare export type Options = Readonly<{ - wait?: boolean, - background?: boolean, - newInstance?: boolean, - allowNonzeroExitCode?: boolean, - ... - }>; - - declare type open = ( - target: string, - options?: Options, - ) => Promise; - - declare module.exports: open; -} diff --git a/flow-typed/npm/open_v8.x.x.js b/flow-typed/npm/open_v8.x.x.js new file mode 100644 index 000000000000..0c77a236170d --- /dev/null +++ b/flow-typed/npm/open_v8.x.x.js @@ -0,0 +1,50 @@ +/** + * 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 + * @format + */ + +declare module 'open' { + import type {ChildProcess} from 'child_process'; + + declare export type AppName = 'chrome' | 'firefox' | 'edge'; + + declare export type App = Readonly<{ + name: string | ReadonlyArray, + arguments?: ReadonlyArray, + }>; + + declare export type Options = Readonly<{ + wait?: boolean, + background?: boolean, + newInstance?: boolean, + allowNonzeroExitCode?: boolean, + app?: App | ReadonlyArray, + ... + }>; + + declare export type OpenAppOptions = Readonly<{ + wait?: boolean, + background?: boolean, + newInstance?: boolean, + allowNonzeroExitCode?: boolean, + arguments?: ReadonlyArray, + ... + }>; + + declare module.exports: (( + target: string, + options?: Options, + ) => Promise) & { + apps: Record>, + openApp: ( + name: string | ReadonlyArray, + options?: OpenAppOptions, + ) => Promise, + ... + }; +} diff --git a/packages/dev-middleware/package.json b/packages/dev-middleware/package.json index 8cbf9e2b8109..814097db9e2c 100644 --- a/packages/dev-middleware/package.json +++ b/packages/dev-middleware/package.json @@ -34,13 +34,11 @@ "@isaacs/ttlcache": "^1.4.1", "@react-native/debugger-frontend": "0.87.0-main", "@react-native/debugger-shell": "0.87.0-main", - "chrome-launcher": "^0.15.2", - "chromium-edge-launcher": "^0.3.0", "connect": "^3.6.5", "debug": "^4.4.0", "invariant": "^2.2.4", "nullthrows": "^1.1.1", - "open": "^7.0.3", + "open": "^8.4.2", "serve-static": "^1.16.2", "ws": "^7.5.10" }, diff --git a/packages/dev-middleware/src/utils/DefaultToolLauncher.js b/packages/dev-middleware/src/utils/DefaultToolLauncher.js index c62c86aeb034..8f8d89961d8b 100644 --- a/packages/dev-middleware/src/utils/DefaultToolLauncher.js +++ b/packages/dev-middleware/src/utils/DefaultToolLauncher.js @@ -14,11 +14,10 @@ const { unstable_prepareDebuggerShell, unstable_spawnDebuggerShellWithArgs, } = require('@react-native/debugger-shell'); -const ChromeLauncher = require('chrome-launcher'); -const {Launcher: EdgeLauncher} = require('chromium-edge-launcher'); -const {spawn} = require('node:child_process'); const open = require('open'); +const {apps, openApp} = open; + /** * Default `DevToolLauncher` implementation which handles opening apps on the * local machine. @@ -29,44 +28,27 @@ const DefaultToolLauncher = { assertMockedInTests(); } - let chromePath; - + // NOTE: Since 0.88 this is a simplified approach, since app launching is + // now handled by `launchDebuggerShell`. Frameworks may still override + // `DevToolLauncher` with an improved fallback stack. try { - // Locate Chrome installation path, will throw if not found - chromePath = ChromeLauncher.getChromePath(); - } catch (e) { - // Fall back to Microsoft Edge - chromePath = EdgeLauncher.getFirstInstallation(); - } - - if (chromePath == null) { + const subprocess = await openApp(apps.chrome, { + arguments: [`--app=${url}`], + newInstance: true, + }); + await new Promise((resolve, reject) => { + subprocess.once('error', reject); + subprocess.once('exit', code => { + code === 0 + ? resolve() + : reject(new Error(`openApp exited with code ${code}`)); + }); + }); + } catch (e: unknown) { // Fall back to default browser - the frontend will warn if the browser // is not supported. await open(url); - return; } - - const chromeFlags = [`--app=${url}`, '--window-size=1200,600']; - - return new Promise((resolve, reject) => { - const childProcess = spawn(chromePath, chromeFlags, { - detached: true, - stdio: 'ignore', - }); - - childProcess.on('data', () => { - resolve(); - }); - childProcess.on('close', (code: number) => { - if (code !== 0) { - reject( - new Error( - `Failed to launch debugger app window: ${chromePath} exited with code ${code}`, - ), - ); - } - }); - }); }, async launchDebuggerShell(url: string, windowKey: string): Promise { diff --git a/yarn.lock b/yarn.lock index 27448ce04351..38f45d7f6f40 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3314,27 +3314,6 @@ chardet@^0.7.0: resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== -chrome-launcher@^0.15.2: - version "0.15.2" - resolved "https://registry.yarnpkg.com/chrome-launcher/-/chrome-launcher-0.15.2.tgz#4e6404e32200095fdce7f6a1e1004f9bd36fa5da" - integrity sha512-zdLEwNo3aUVzIhKhTtXfxhdvZhUghrnmkvcAq2NoDd+LeOHKf03H5jwZ8T/STsAlzyALkBVK552iaG1fGf1xVQ== - dependencies: - "@types/node" "*" - escape-string-regexp "^4.0.0" - is-wsl "^2.2.0" - lighthouse-logger "^1.0.0" - -chromium-edge-launcher@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/chromium-edge-launcher/-/chromium-edge-launcher-0.3.0.tgz#34d5ca8142fc059ea2b4482bdcb184393a399ffe" - integrity sha512-p03azHlGjtyRvFEee3cyvtsRYdniSkwjkzmM/KmVnqT5d7QkkwpJBhis/zCLMYdQMVJ5tt140TBNqqrZPaWeFA== - dependencies: - "@types/node" "*" - escape-string-regexp "^4.0.0" - is-wsl "^2.2.0" - lighthouse-logger "^1.0.0" - mkdirp "^1.0.4" - ci-info@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" @@ -3670,7 +3649,7 @@ dayjs@^1.8.15: resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.13.tgz#92430b0139055c3ebb60150aa13e860a4b5a366c" integrity sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg== -debug@2.6.9, debug@^2.6.9: +debug@2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== @@ -3777,6 +3756,11 @@ define-data-property@^1.0.1, define-data-property@^1.1.4: es-errors "^1.3.0" gopd "^1.0.1" +define-lazy-prop@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f" + integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og== + define-properties@^1.1.3, define-properties@^1.2.0, define-properties@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c" @@ -5534,7 +5518,7 @@ is-decimal@^2.0.0: resolved "https://registry.yarnpkg.com/is-decimal/-/is-decimal-2.0.1.tgz#9469d2dc190d0214fd87d78b78caecc0cc14eef7" integrity sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A== -is-docker@^2.0.0: +is-docker@^2.0.0, is-docker@^2.1.1: version "2.2.1" resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== @@ -5775,7 +5759,7 @@ is-wsl@^1.1.0: resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" integrity sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw== -is-wsl@^2.1.1, is-wsl@^2.2.0: +is-wsl@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== @@ -6442,14 +6426,6 @@ levn@^0.4.1: prelude-ls "^1.2.1" type-check "~0.4.0" -lighthouse-logger@^1.0.0: - version "1.4.2" - resolved "https://registry.yarnpkg.com/lighthouse-logger/-/lighthouse-logger-1.4.2.tgz#aef90f9e97cd81db367c7634292ee22079280aaa" - integrity sha512-gPWxznF6TKmUHrOQjlVo2UbaL2EJ71mb2CCeRs/2qBpi4L/g4LUVc9+3lKQ6DTUZwJswfM7ainGrLO1+fOqa2g== - dependencies: - debug "^2.6.9" - marky "^1.2.2" - lines-and-columns@^1.1.6: version "1.2.4" resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" @@ -6666,11 +6642,6 @@ markdownlint@0.37.4: micromark-extension-math "3.1.0" micromark-util-types "2.0.1" -marky@^1.2.2: - version "1.2.5" - resolved "https://registry.yarnpkg.com/marky/-/marky-1.2.5.tgz#55796b688cbd72390d2d399eaaf1832c9413e3c0" - integrity sha512-q9JtQJKjpsVxCRVgQ+WapguSbKC3SQ5HEzFGPAJMStgh3QjCawp00UKv3MTTAArTmGmmPUvllHZoNbZ3gs0I+Q== - math-intrinsics@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9" @@ -7527,13 +7498,14 @@ open@^6.2.0: dependencies: is-wsl "^1.1.0" -open@^7.0.3: - version "7.4.2" - resolved "https://registry.yarnpkg.com/open/-/open-7.4.2.tgz#b8147e26dcf3e426316c730089fd71edd29c2321" - integrity sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q== +open@^8.4.2: + version "8.4.2" + resolved "https://registry.yarnpkg.com/open/-/open-8.4.2.tgz#5b5ffe2a8f793dcd2aad73e550cb87b59cb084f9" + integrity sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ== dependencies: - is-docker "^2.0.0" - is-wsl "^2.1.1" + define-lazy-prop "^2.0.0" + is-docker "^2.1.1" + is-wsl "^2.2.0" optionator@^0.9.3: version "0.9.4"