Skip to content

Commit 1b5d826

Browse files
huntiefacebook-github-bot
authored andcommitted
Add --experimental-debugger-frontend flag, restore 0.72 flow as base
Summary: This changeset allows users to opt into the new debugger frontend experience by passing `--experimental-debugger` to `react-native start`. **We are defaulting this option to `true`** for now, but will continue to evaluate this feature before 0.73 ships. It restores Flipper (via `flipper://`) as the default handling for `/open-debugger` (matching 0.72 behaviour) when this flag is not enabled. Detailed changes: - Replaces `enableCustomDebuggerFrontend` experiment in `dev-middleware` with `enableNewDebuggerFrontend`. The latter now hard-swaps between the Flipper and new launch flows. - Removes now-unused switching of `devtoolsFrontendUrl`. - Implements `deprecated_openFlipperMiddleware` (matching previous RN CLI implementation). - Disables "`j` to debug" key handler by default. - Marks "`j` to debug" and `/open-debugger` console logs as experimental. Changelog: [Changed][General] Gate new debugger frontend behind `--experimental-debugger-frontend` flag, restore Flipper as base launch flow Differential Revision: D50084590 fbshipit-source-id: 4fdff491fdb1217e80abb6d7a1d1dfb22180b0d3
1 parent 92c02cd commit 1b5d826

File tree

11 files changed

+153
-51
lines changed

11 files changed

+153
-51
lines changed

flow-typed/npm/open_v7.x.x.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/**
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @flow strict
8+
* @format
9+
* @oncall react_native
10+
*/
11+
12+
declare module 'open' {
13+
import type {ChildProcess} from 'child_process';
14+
15+
declare export type Options = $ReadOnly<{
16+
wait?: boolean,
17+
background?: boolean,
18+
newInstance?: boolean,
19+
allowNonzeroExitCode?: boolean,
20+
...
21+
}>;
22+
23+
declare type open = (
24+
target: string,
25+
options?: Options,
26+
) => Promise<ChildProcess>;
27+
28+
declare module.exports: open;
29+
}

packages/community-cli-plugin/src/commands/start/attachKeyHandlers.js

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,15 @@ export default function attachKeyHandlers({
2424
cliConfig,
2525
devServerUrl,
2626
messageSocket,
27+
experimentalDebuggerFrontend,
2728
}: {
2829
cliConfig: Config,
2930
devServerUrl: string,
3031
messageSocket: $ReadOnly<{
3132
broadcast: (type: string, params?: Record<string, mixed> | null) => void,
3233
...
3334
}>,
35+
experimentalDebuggerFrontend: boolean,
3436
}) {
3537
if (process.stdin.isTTY !== true) {
3638
logger.debug('Interactive mode is not supported in this environment');
@@ -76,6 +78,9 @@ export default function attachKeyHandlers({
7678
).stdout?.pipe(process.stdout);
7779
break;
7880
case 'j':
81+
if (!experimentalDebuggerFrontend) {
82+
return;
83+
}
7984
await fetch(devServerUrl + '/open-debugger', {method: 'POST'});
8085
break;
8186
case CTRL_C:
@@ -92,12 +97,16 @@ export default function attachKeyHandlers({
9297
keyPressHandler.startInterceptingKeyStrokes();
9398

9499
logger.log(
95-
`
96-
${chalk.bold('i')} - run on iOS
97-
${chalk.bold('a')} - run on Android
98-
${chalk.bold('d')} - open Dev Menu
99-
${chalk.bold('j')} - open debugger
100-
${chalk.bold('r')} - reload app
101-
`,
100+
[
101+
'',
102+
`${chalk.bold('i')} - run on iOS`,
103+
`${chalk.bold('a')} - run on Android`,
104+
`${chalk.bold('d')} - open Dev Menu`,
105+
...(experimentalDebuggerFrontend
106+
? [`${chalk.bold('j')} - open debugger (experimental)`]
107+
: []),
108+
`${chalk.bold('r')} - reload app`,
109+
'',
110+
].join('\n'),
102111
);
103112
}

packages/community-cli-plugin/src/commands/start/index.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,17 @@ const startCommand: Command = {
9595
name: '--no-interactive',
9696
description: 'Disables interactive mode',
9797
},
98+
{
99+
name: '--experimental-debugger [bool]',
100+
description:
101+
"[Experimental] Enable the new debugger experience and 'j' to " +
102+
'debug. In React Native 0.73, this enables the new frontend ' +
103+
'experience only: connection reliability and some basic features are' +
104+
'unstable.',
105+
parse: (val: ?string): boolean =>
106+
val !== undefined && val !== 'false' && val !== '0',
107+
default: true,
108+
},
98109
],
99110
};
100111

packages/community-cli-plugin/src/commands/start/runServer.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ export type StartCommandArgs = {
3333
assetPlugins?: string[],
3434
cert?: string,
3535
customLogReporterPath?: string,
36+
experimentalDebugger: boolean,
3637
host?: string,
3738
https?: boolean,
3839
maxWorkers?: number,
@@ -118,7 +119,7 @@ async function runServer(
118119
logger,
119120
unstable_experiments: {
120121
// NOTE: Only affects the /open-debugger endpoint
121-
enableCustomDebuggerFrontend: true,
122+
enableNewDebuggerFrontend: args.experimentalDebugger,
122123
},
123124
});
124125

@@ -138,6 +139,7 @@ async function runServer(
138139
cliConfig: ctx,
139140
devServerUrl,
140141
messageSocket: messageSocketEndpoint,
142+
experimentalDebuggerFrontend: args.experimentalDebugger,
141143
});
142144
}
143145
},

packages/dev-middleware/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
"connect": "^3.6.5",
3030
"debug": "^2.2.0",
3131
"node-fetch": "^2.2.0",
32+
"open": "^7.0.3",
3233
"serve-static": "^1.13.1",
3334
"temp-dir": "^2.0.0"
3435
},

packages/dev-middleware/src/createDevMiddleware.js

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import reactNativeDebuggerFrontendPath from '@react-native/debugger-frontend';
1919
import connect from 'connect';
2020
import path from 'path';
2121
import serveStaticMiddleware from 'serve-static';
22+
import deprecated_openFlipperMiddleware from './middleware/deprecated_openFlipperMiddleware';
2223
import openDebuggerMiddleware from './middleware/openDebuggerMiddleware';
2324
import InspectorProxy from './inspector-proxy/InspectorProxy';
2425
import DefaultBrowserLauncher from './utils/DefaultBrowserLauncher';
@@ -85,14 +86,18 @@ export default function createDevMiddleware({
8586
const middleware = connect()
8687
.use(
8788
'/open-debugger',
88-
openDebuggerMiddleware({
89-
serverBaseUrl,
90-
inspectorProxy,
91-
browserLauncher: unstable_browserLauncher,
92-
eventReporter: unstable_eventReporter,
93-
experiments,
94-
logger,
95-
}),
89+
experiments.enableNewDebuggerFrontend
90+
? openDebuggerMiddleware({
91+
serverBaseUrl,
92+
inspectorProxy,
93+
browserLauncher: unstable_browserLauncher,
94+
eventReporter: unstable_eventReporter,
95+
experiments,
96+
logger,
97+
})
98+
: deprecated_openFlipperMiddleware({
99+
logger,
100+
}),
96101
)
97102
.use(
98103
'/debugger-frontend',
@@ -110,7 +115,7 @@ export default function createDevMiddleware({
110115

111116
function getExperiments(config: ExperimentsConfig): Experiments {
112117
return {
113-
enableCustomDebuggerFrontend: config.enableCustomDebuggerFrontend ?? false,
118+
enableNewDebuggerFrontend: config.enableNewDebuggerFrontend ?? false,
114119
enableOpenDebuggerRedirect: config.enableOpenDebuggerRedirect ?? false,
115120
};
116121
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/**
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @flow strict-local
8+
* @format
9+
* @oncall react_native
10+
*/
11+
12+
import type {NextHandleFunction} from 'connect';
13+
import type {IncomingMessage, ServerResponse} from 'http';
14+
import type {Logger} from '../types/Logger';
15+
16+
import open from 'open';
17+
18+
const FLIPPER_SELF_CONNECT_URL =
19+
'flipper://null/Hermesdebuggerrn?device=React%20Native';
20+
21+
type Options = $ReadOnly<{
22+
logger?: Logger,
23+
}>;
24+
25+
/**
26+
* Open the legacy Flipper debugger (Hermes).
27+
*
28+
* @deprecated This replicates the pre-0.73 workflow of opening Flipper via the
29+
* `flipper://` URL scheme, failing if Flipper is not installed locally. This
30+
* flow will be removed in a future version.
31+
*/
32+
export default function deprecated_openFlipperMiddleware({
33+
logger,
34+
}: Options): NextHandleFunction {
35+
return async (
36+
req: IncomingMessage,
37+
res: ServerResponse,
38+
next: (err?: Error) => void,
39+
) => {
40+
if (req.method === 'POST') {
41+
logger?.info('Launching JS debugger...');
42+
43+
try {
44+
logger?.warn(
45+
'Attempting to debug JS in Flipper (deprecated). This requires ' +
46+
'Flipper to be installed on your system to handle the ' +
47+
"'flipper://' URL scheme.",
48+
);
49+
await open(FLIPPER_SELF_CONNECT_URL);
50+
res.end();
51+
} catch (e) {
52+
logger?.error(
53+
'Error launching Flipper: ' + e.message ?? 'Unknown error',
54+
);
55+
res.writeHead(500);
56+
res.end();
57+
}
58+
}
59+
};
60+
}

packages/dev-middleware/src/middleware/openDebuggerMiddleware.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ export default function openDebuggerMiddleware({
7272
if (typeof appId === 'string') {
7373
logger?.info(
7474
(launchType === 'launch' ? 'Launching' : 'Redirecting to') +
75-
' JS debugger...',
75+
' JS debugger (experimental)...',
7676
);
7777
target = targets.find(_target => _target.description === appId);
7878
} else {
@@ -108,7 +108,6 @@ export default function openDebuggerMiddleware({
108108
getDevToolsFrontendUrl(
109109
target.webSocketDebuggerUrl,
110110
serverBaseUrl,
111-
experiments,
112111
),
113112
),
114113
);
@@ -120,7 +119,6 @@ export default function openDebuggerMiddleware({
120119
target.webSocketDebuggerUrl,
121120
// Use a relative URL.
122121
'',
123-
experiments,
124122
),
125123
});
126124
res.end();

packages/dev-middleware/src/types/Experiments.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,11 @@
1010

1111
export type Experiments = $ReadOnly<{
1212
/**
13-
* Enables the use of the custom debugger frontend (@react-native/debugger-frontend)
14-
* in the /open-debugger endpoint.
13+
* Enables the new JS debugger launch flow and custom debugger frontend
14+
* (@react-native/debugger-frontend). When disabled, /open-debugger will
15+
* trigger the legacy Flipper connection flow.
1516
*/
16-
enableCustomDebuggerFrontend: boolean,
17+
enableNewDebuggerFrontend: boolean,
1718

1819
/**
1920
* Enables the handling of GET requests in the /open-debugger endpoint,

packages/dev-middleware/src/utils/getDevToolsFrontendUrl.js

Lines changed: 5 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -9,40 +9,18 @@
99
* @oncall react_native
1010
*/
1111

12-
import type {Experiments} from '../types/Experiments';
13-
14-
/**
15-
* The Chrome DevTools frontend revision to use. This should be set to the
16-
* latest version known to be compatible with Hermes.
17-
*
18-
* Revision should be the full identifier from:
19-
* https://chromium.googlesource.com/chromium/src.git
20-
*/
21-
const DEVTOOLS_FRONTEND_REV = 'd9568d04d7dd79269c5a655d7ada69650c5a8336'; // Chrome 100.0.4896.75
22-
2312
/**
24-
* Construct the URL to Chrome DevTools connected to a given debugger target.
13+
* Get the DevTools frontend URL to debug a given React Native CDP target.
2514
*/
2615
export default function getDevToolsFrontendUrl(
2716
webSocketDebuggerUrl: string,
2817
devServerUrl: string,
29-
experiments: Experiments,
3018
): string {
3119
const scheme = new URL(webSocketDebuggerUrl).protocol.slice(0, -1);
32-
const webSocketUrlWithoutProtocol = webSocketDebuggerUrl.replace(
33-
/^wss?:\/\//,
34-
'',
20+
const appUrl = `${devServerUrl}/debugger-frontend/rn_inspector.html`;
21+
const webSocketUrlWithoutProtocol = encodeURIComponent(
22+
webSocketDebuggerUrl.replace(/^wss?:\/\//, ''),
3523
);
3624

37-
if (experiments.enableCustomDebuggerFrontend) {
38-
const urlBase = `${devServerUrl}/debugger-frontend/rn_inspector.html`;
39-
return `${urlBase}?${scheme}=${encodeURIComponent(
40-
webSocketUrlWithoutProtocol,
41-
)}&sources.hide_add_folder=true`;
42-
}
43-
44-
const urlBase = `https://chrome-devtools-frontend.appspot.com/serve_rev/@${DEVTOOLS_FRONTEND_REV}/devtools_app.html`;
45-
return `${urlBase}?panel=console&${scheme}=${encodeURIComponent(
46-
webSocketUrlWithoutProtocol,
47-
)}`;
25+
return `${appUrl}?${scheme}=${webSocketUrlWithoutProtocol}&sources.hide_add_folder=true`;
4826
}

yarn.lock

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5983,7 +5983,7 @@ is-wsl@^1.1.0:
59835983
resolved "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d"
59845984
integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=
59855985

5986-
is-wsl@^2.2.0:
5986+
is-wsl@^2.1.1, is-wsl@^2.2.0:
59875987
version "2.2.0"
59885988
resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271"
59895989
integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==
@@ -7617,6 +7617,14 @@ open@^6.2.0:
76177617
dependencies:
76187618
is-wsl "^1.1.0"
76197619

7620+
open@^7.0.3:
7621+
version "7.4.2"
7622+
resolved "https://registry.yarnpkg.com/open/-/open-7.4.2.tgz#b8147e26dcf3e426316c730089fd71edd29c2321"
7623+
integrity sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==
7624+
dependencies:
7625+
is-docker "^2.0.0"
7626+
is-wsl "^2.1.1"
7627+
76207628
optionator@^0.9.1:
76217629
version "0.9.1"
76227630
resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499"

0 commit comments

Comments
 (0)