Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add --experimental-debugger-frontend flag, restore 0.72 flow as base #40766

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions flow-typed/npm/open_v7.x.x.js
Original file line number Diff line number Diff line change
@@ -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;
}
122 changes: 122 additions & 0 deletions flow-typed/npm/serve-static_v1.x.x.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/**
* 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 'serve-static' {
import type {NextHandleFunction} from 'connect';
import type http from 'http';

declare export type Options = $ReadOnly<{
/**
* Enable or disable accepting ranged requests, defaults to true. Disabling
* this will not send `Accept-Ranges` and ignore the contents of the
* `Range` request header.
*/
acceptRanges?: boolean,

/**
* Enable or disable setting `Cache-Control` response header, defaults to
* true. Disabling this will ignore the `immutable` and `maxAge` options.
*/
cacheControl?: boolean,

/**
* Set how "dotfiles" are treated when encountered. A dotfile is a file or
* directory that begins with a dot (".").
*
* Note this check is done on the path itself without checking if the path
* actually exists on the disk. If `root` is specified, only the dotfiles
* above the root are checked (i.e. the root itself can be within a dotfile
* when when set to "deny").
*
* The default value is 'ignore'.
*
* 'allow' No special treatment for dotfiles
* 'deny' Send a 403 for any request for a dotfile
* 'ignore' Pretend like the dotfile does not exist and call next()
*/
dotfiles?: string,

/**
* Enable or disable etag generation, defaults to true.
*/
etag?: boolean,

/**
* Set file extension fallbacks. When set, if a file is not found, the
* given extensions will be added to the file name and search for.
* The first that exists will be served. Example: ['html', 'htm'].
*
* The default value is false.
*/
extensions?: Array<string> | false,

/**
* Let client errors fall-through as unhandled requests, otherwise forward
* a client error.
*
* The default value is true.
*/
fallthrough?: boolean,

/**
* Enable or disable the immutable directive in the `Cache-Control` response
* header.
*
* If enabled, the `maxAge` option should also be specified to enable
* caching. The immutable directive will prevent supported clients from
* making conditional requests during the life of the maxAge option to
* check if the file has changed.
*/
immutable?: boolean,

/**
* By default this module will send "index.html" files in response to a
* request on a directory. To disable this set false or to supply a new
* index pass a string or an array in preferred order.
*/
index?: boolean | string | Array<string>,

/**
* Enable or disable `Last-Modified` header, defaults to true. Uses the file
* system's last modified value.
*/
lastModified?: boolean,

/**
* Provide a max-age in milliseconds for http caching, defaults to 0. This
* can also be a string accepted by the `ms` module.
*/
maxAge?: number | string,

/**
* Redirect to trailing "/" when the pathname is a dir. Defaults to true.
*/
redirect?: boolean,

/**
* Function to set custom headers on response. Alterations to the headers
* need to occur synchronously.
*
* The function is called as `fn(res, path, stat)`, where the arguments are:
* `res` the response object
* `path` the file path that is being sent
* `stat` the stat object of the file that is being sent
*/
setHeaders?: (res: http.ServerResponse, path: string, stat: any) => any,
}>;

declare type serveStatic = (
root: string,
options?: Options,
) => NextHandleFunction;

declare module.exports: serveStatic;
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,15 @@ export default function attachKeyHandlers({
cliConfig,
devServerUrl,
messageSocket,
experimentalDebuggerFrontend,
}: {
cliConfig: Config,
devServerUrl: string,
messageSocket: $ReadOnly<{
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');
Expand Down Expand Up @@ -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:
Expand All @@ -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'),
);
}
10 changes: 10 additions & 0 deletions packages/community-cli-plugin/src/commands/start/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
},
],
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export type StartCommandArgs = {
assetPlugins?: string[],
cert?: string,
customLogReporterPath?: string,
experimentalDebugger: boolean,
host?: string,
https?: boolean,
maxWorkers?: number,
Expand Down Expand Up @@ -118,7 +119,7 @@ async function runServer(
logger,
unstable_experiments: {
// NOTE: Only affects the /open-debugger endpoint
enableCustomDebuggerFrontend: true,
enableNewDebugger: args.experimentalDebugger,
},
});

Expand All @@ -138,6 +139,7 @@ async function runServer(
cliConfig: ctx,
devServerUrl,
messageSocket: messageSocketEndpoint,
experimentalDebuggerFrontend: args.experimentalDebugger,
});
}
},
Expand Down
4 changes: 4 additions & 0 deletions packages/dev-middleware/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ Returns the list of available WebSocket targets for all connected React Native a

Returns version metadata used by Chrome DevTools.

#### GET `/debugger-frontend`

Subpaths of this endpoint are reserved to serve the JavaScript debugger frontend.

#### POST `/open-debugger`

Open the JavaScript debugger for a given CDP target (direct Hermes debugging).
Expand Down
1 change: 1 addition & 0 deletions packages/dev-middleware/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
},
Expand Down
24 changes: 14 additions & 10 deletions packages/dev-middleware/src/createDevMiddleware.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ import type {Logger} from './types/Logger';
import reactNativeDebuggerFrontendPath from '@react-native/debugger-frontend';
import connect from 'connect';
import path from 'path';
// $FlowFixMe[untyped-import] TODO: type serve-static
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';
Expand Down Expand Up @@ -86,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',
Expand All @@ -111,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,
};
}
Original file line number Diff line number Diff line change
@@ -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();
}
}
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -108,7 +108,6 @@ export default function openDebuggerMiddleware({
getDevToolsFrontendUrl(
target.webSocketDebuggerUrl,
serverBaseUrl,
experiments,
),
),
);
Expand All @@ -120,7 +119,6 @@ export default function openDebuggerMiddleware({
target.webSocketDebuggerUrl,
// Use a relative URL.
'',
experiments,
),
});
res.end();
Expand Down
Loading