Add --experimental-debugger-frontend flag, restore 0.72 flow as base (#40766)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/40766 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 `enableNewDebugger`. 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` flag, restore Flipper as base launch flow Reviewed By: motiz88 Differential Revision: D50084590 fbshipit-source-id: 5234634f20110cb7933b1787bd2c86f645411fff
This commit is contained in:
Родитель
4dcd5f1065
Коммит
9e068ac163
|
@ -0,0 +1,29 @@
|
|||
/**
|
||||
* 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
|
||||
* @oncall react_native
|
||||
*/
|
||||
|
||||
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<ChildProcess>;
|
||||
|
||||
declare module.exports: open;
|
||||
}
|
|
@ -24,6 +24,7 @@ export default function attachKeyHandlers({
|
|||
cliConfig,
|
||||
devServerUrl,
|
||||
messageSocket,
|
||||
experimentalDebuggerFrontend,
|
||||
}: {
|
||||
cliConfig: Config,
|
||||
devServerUrl: string,
|
||||
|
@ -31,6 +32,7 @@ export default function attachKeyHandlers({
|
|||
broadcast: (type: string, params?: Record<string, mixed> | null) => void,
|
||||
...
|
||||
}>,
|
||||
experimentalDebuggerFrontend: boolean,
|
||||
}) {
|
||||
if (process.stdin.isTTY !== true) {
|
||||
logger.debug('Interactive mode is not supported in this environment');
|
||||
|
@ -76,6 +78,9 @@ export default function attachKeyHandlers({
|
|||
).stdout?.pipe(process.stdout);
|
||||
break;
|
||||
case 'j':
|
||||
if (!experimentalDebuggerFrontend) {
|
||||
return;
|
||||
}
|
||||
await fetch(devServerUrl + '/open-debugger', {method: 'POST'});
|
||||
break;
|
||||
case CTRL_C:
|
||||
|
@ -92,12 +97,16 @@ export default function attachKeyHandlers({
|
|||
keyPressHandler.startInterceptingKeyStrokes();
|
||||
|
||||
logger.log(
|
||||
`
|
||||
${chalk.bold('i')} - run on iOS
|
||||
${chalk.bold('a')} - run on Android
|
||||
${chalk.bold('d')} - open Dev Menu
|
||||
${chalk.bold('j')} - open debugger
|
||||
${chalk.bold('r')} - reload app
|
||||
`,
|
||||
[
|
||||
'',
|
||||
`${chalk.bold('i')} - run on iOS`,
|
||||
`${chalk.bold('a')} - run on Android`,
|
||||
`${chalk.bold('d')} - open Dev Menu`,
|
||||
...(experimentalDebuggerFrontend
|
||||
? [`${chalk.bold('j')} - open debugger (experimental)`]
|
||||
: []),
|
||||
`${chalk.bold('r')} - reload app`,
|
||||
'',
|
||||
].join('\n'),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -95,6 +95,16 @@ const startCommand: Command = {
|
|||
name: '--no-interactive',
|
||||
description: 'Disables interactive mode',
|
||||
},
|
||||
{
|
||||
name: '--experimental-debugger [bool]',
|
||||
description:
|
||||
"[Experimental] Enable the new debugger experience and 'j' to " +
|
||||
'debug. This enables the new frontend experience only: connection ' +
|
||||
'reliability and some basic features are unstable in this release.',
|
||||
parse: (val: ?string): boolean =>
|
||||
val !== undefined && val !== 'false' && val !== '0',
|
||||
default: true,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ export type StartCommandArgs = {
|
|||
assetPlugins?: string[],
|
||||
cert?: string,
|
||||
customLogReporterPath?: string,
|
||||
experimentalDebugger: boolean,
|
||||
host?: string,
|
||||
https?: boolean,
|
||||
maxWorkers?: number,
|
||||
|
@ -118,7 +119,7 @@ async function runServer(
|
|||
logger,
|
||||
unstable_experiments: {
|
||||
// NOTE: Only affects the /open-debugger endpoint
|
||||
enableCustomDebuggerFrontend: true,
|
||||
enableNewDebugger: args.experimentalDebugger,
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -138,6 +139,7 @@ async function runServer(
|
|||
cliConfig: ctx,
|
||||
devServerUrl,
|
||||
messageSocket: messageSocketEndpoint,
|
||||
experimentalDebuggerFrontend: args.experimentalDebugger,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
"connect": "^3.6.5",
|
||||
"debug": "^2.2.0",
|
||||
"node-fetch": "^2.2.0",
|
||||
"open": "^7.0.3",
|
||||
"serve-static": "^1.13.1",
|
||||
"temp-dir": "^2.0.0"
|
||||
},
|
||||
|
|
|
@ -19,6 +19,7 @@ import reactNativeDebuggerFrontendPath from '@react-native/debugger-frontend';
|
|||
import connect from 'connect';
|
||||
import path from 'path';
|
||||
import serveStaticMiddleware from 'serve-static';
|
||||
import deprecated_openFlipperMiddleware from './middleware/deprecated_openFlipperMiddleware';
|
||||
import openDebuggerMiddleware from './middleware/openDebuggerMiddleware';
|
||||
import InspectorProxy from './inspector-proxy/InspectorProxy';
|
||||
import DefaultBrowserLauncher from './utils/DefaultBrowserLauncher';
|
||||
|
@ -85,14 +86,18 @@ export default function createDevMiddleware({
|
|||
const middleware = connect()
|
||||
.use(
|
||||
'/open-debugger',
|
||||
openDebuggerMiddleware({
|
||||
serverBaseUrl,
|
||||
inspectorProxy,
|
||||
browserLauncher: unstable_browserLauncher,
|
||||
eventReporter: unstable_eventReporter,
|
||||
experiments,
|
||||
logger,
|
||||
}),
|
||||
experiments.enableNewDebugger
|
||||
? openDebuggerMiddleware({
|
||||
serverBaseUrl,
|
||||
inspectorProxy,
|
||||
browserLauncher: unstable_browserLauncher,
|
||||
eventReporter: unstable_eventReporter,
|
||||
experiments,
|
||||
logger,
|
||||
})
|
||||
: deprecated_openFlipperMiddleware({
|
||||
logger,
|
||||
}),
|
||||
)
|
||||
.use(
|
||||
'/debugger-frontend',
|
||||
|
@ -110,7 +115,7 @@ export default function createDevMiddleware({
|
|||
|
||||
function getExperiments(config: ExperimentsConfig): Experiments {
|
||||
return {
|
||||
enableCustomDebuggerFrontend: config.enableCustomDebuggerFrontend ?? false,
|
||||
enableNewDebugger: config.enableNewDebugger ?? false,
|
||||
enableOpenDebuggerRedirect: config.enableOpenDebuggerRedirect ?? false,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
/**
|
||||
* 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
|
||||
* @oncall react_native
|
||||
*/
|
||||
|
||||
import type {NextHandleFunction} from 'connect';
|
||||
import type {IncomingMessage, ServerResponse} from 'http';
|
||||
import type {Logger} from '../types/Logger';
|
||||
|
||||
import open from 'open';
|
||||
|
||||
const FLIPPER_SELF_CONNECT_URL =
|
||||
'flipper://null/Hermesdebuggerrn?device=React%20Native';
|
||||
|
||||
type Options = $ReadOnly<{
|
||||
logger?: Logger,
|
||||
}>;
|
||||
|
||||
/**
|
||||
* Open the legacy Flipper debugger (Hermes).
|
||||
*
|
||||
* @deprecated This replicates the pre-0.73 workflow of opening Flipper via the
|
||||
* `flipper://` URL scheme, failing if Flipper is not installed locally. This
|
||||
* flow will be removed in a future version.
|
||||
*/
|
||||
export default function deprecated_openFlipperMiddleware({
|
||||
logger,
|
||||
}: Options): NextHandleFunction {
|
||||
return async (
|
||||
req: IncomingMessage,
|
||||
res: ServerResponse,
|
||||
next: (err?: Error) => void,
|
||||
) => {
|
||||
if (req.method === 'POST') {
|
||||
logger?.info('Launching JS debugger...');
|
||||
|
||||
try {
|
||||
logger?.warn(
|
||||
'Attempting to debug JS in Flipper (deprecated). This requires ' +
|
||||
'Flipper to be installed on your system to handle the ' +
|
||||
"'flipper://' URL scheme.",
|
||||
);
|
||||
await open(FLIPPER_SELF_CONNECT_URL);
|
||||
res.end();
|
||||
} catch (e) {
|
||||
logger?.error(
|
||||
'Error launching Flipper: ' + e.message ?? 'Unknown error',
|
||||
);
|
||||
res.writeHead(500);
|
||||
res.end();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
|
@ -72,7 +72,7 @@ export default function openDebuggerMiddleware({
|
|||
if (typeof appId === 'string') {
|
||||
logger?.info(
|
||||
(launchType === 'launch' ? 'Launching' : 'Redirecting to') +
|
||||
' JS debugger...',
|
||||
' JS debugger (experimental)...',
|
||||
);
|
||||
target = targets.find(_target => _target.description === appId);
|
||||
} else {
|
||||
|
@ -108,7 +108,6 @@ export default function openDebuggerMiddleware({
|
|||
getDevToolsFrontendUrl(
|
||||
target.webSocketDebuggerUrl,
|
||||
serverBaseUrl,
|
||||
experiments,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
@ -120,7 +119,6 @@ export default function openDebuggerMiddleware({
|
|||
target.webSocketDebuggerUrl,
|
||||
// Use a relative URL.
|
||||
'',
|
||||
experiments,
|
||||
),
|
||||
});
|
||||
res.end();
|
||||
|
|
|
@ -10,10 +10,11 @@
|
|||
|
||||
export type Experiments = $ReadOnly<{
|
||||
/**
|
||||
* Enables the use of the custom debugger frontend (@react-native/debugger-frontend)
|
||||
* in the /open-debugger endpoint.
|
||||
* Enables the new JS debugger launch flow and custom debugger frontend
|
||||
* (@react-native/debugger-frontend). When disabled, /open-debugger will
|
||||
* trigger the legacy Flipper connection flow.
|
||||
*/
|
||||
enableCustomDebuggerFrontend: boolean,
|
||||
enableNewDebugger: boolean,
|
||||
|
||||
/**
|
||||
* Enables the handling of GET requests in the /open-debugger endpoint,
|
||||
|
|
|
@ -9,40 +9,18 @@
|
|||
* @oncall react_native
|
||||
*/
|
||||
|
||||
import type {Experiments} from '../types/Experiments';
|
||||
|
||||
/**
|
||||
* The Chrome DevTools frontend revision to use. This should be set to the
|
||||
* latest version known to be compatible with Hermes.
|
||||
*
|
||||
* Revision should be the full identifier from:
|
||||
* https://chromium.googlesource.com/chromium/src.git
|
||||
*/
|
||||
const DEVTOOLS_FRONTEND_REV = 'd9568d04d7dd79269c5a655d7ada69650c5a8336'; // Chrome 100.0.4896.75
|
||||
|
||||
/**
|
||||
* Construct the URL to Chrome DevTools connected to a given debugger target.
|
||||
* Get the DevTools frontend URL to debug a given React Native CDP target.
|
||||
*/
|
||||
export default function getDevToolsFrontendUrl(
|
||||
webSocketDebuggerUrl: string,
|
||||
devServerUrl: string,
|
||||
experiments: Experiments,
|
||||
): string {
|
||||
const scheme = new URL(webSocketDebuggerUrl).protocol.slice(0, -1);
|
||||
const webSocketUrlWithoutProtocol = webSocketDebuggerUrl.replace(
|
||||
/^wss?:\/\//,
|
||||
'',
|
||||
const appUrl = `${devServerUrl}/debugger-frontend/rn_inspector.html`;
|
||||
const webSocketUrlWithoutProtocol = encodeURIComponent(
|
||||
webSocketDebuggerUrl.replace(/^wss?:\/\//, ''),
|
||||
);
|
||||
|
||||
if (experiments.enableCustomDebuggerFrontend) {
|
||||
const urlBase = `${devServerUrl}/debugger-frontend/rn_inspector.html`;
|
||||
return `${urlBase}?${scheme}=${encodeURIComponent(
|
||||
webSocketUrlWithoutProtocol,
|
||||
)}&sources.hide_add_folder=true`;
|
||||
}
|
||||
|
||||
const urlBase = `https://chrome-devtools-frontend.appspot.com/serve_rev/@${DEVTOOLS_FRONTEND_REV}/devtools_app.html`;
|
||||
return `${urlBase}?panel=console&${scheme}=${encodeURIComponent(
|
||||
webSocketUrlWithoutProtocol,
|
||||
)}`;
|
||||
return `${appUrl}?${scheme}=${webSocketUrlWithoutProtocol}&sources.hide_add_folder=true`;
|
||||
}
|
||||
|
|
10
yarn.lock
10
yarn.lock
|
@ -5983,7 +5983,7 @@ is-wsl@^1.1.0:
|
|||
resolved "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d"
|
||||
integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=
|
||||
|
||||
is-wsl@^2.2.0:
|
||||
is-wsl@^2.1.1, 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==
|
||||
|
@ -7617,6 +7617,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==
|
||||
dependencies:
|
||||
is-docker "^2.0.0"
|
||||
is-wsl "^2.1.1"
|
||||
|
||||
optionator@^0.9.1:
|
||||
version "0.9.1"
|
||||
resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499"
|
||||
|
|
Загрузка…
Ссылка в новой задаче