Skip to content

Commit

Permalink
Replace Metro stdout check with dep_graph_loaded event (facebook#38960)
Browse files Browse the repository at this point in the history
Summary:
Pull Request resolved: facebook#38960

Code cleanup following `cli-plugin-metro` import.

Changelog: [Internal]

Reviewed By: motiz88

Differential Revision: D48188228

fbshipit-source-id: caa370989cebae0a36c20d7d6bfa81781e9cb77c
  • Loading branch information
huntie authored and facebook-github-bot committed Aug 14, 2023
1 parent 8c72640 commit 202a180
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 60 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,63 +11,33 @@

import type {Config} from '@react-native-community/cli-types';

import readline from 'readline';
import {
addInteractionListener,
logger,
hookStdout,
} from '@react-native-community/cli-tools';
import execa from 'execa';
import chalk from 'chalk';
import execa from 'execa';
import readline from 'readline';
import {KeyPressHandler} from '../../utils/KeyPressHandler';

const CTRL_C = '\u0003';
const CTRL_Z = '\u0026';

function printWatchModeInstructions() {
logger.log(
`${chalk.bold('r')} - reload the app\n${chalk.bold(
'd',
)} - open developer menu\n${chalk.bold('i')} - run on iOS\n${chalk.bold(
'a',
)} - run on Android`,
);
}

function enableWatchMode(
export default function attachKeyHandlers(
cliConfig: Config,
messageSocket: $ReadOnly<{
broadcast: (type: string, params?: Record<string, mixed> | null) => void,
...
}>,
ctx: Config,
) {
// We need to set this to true to catch key presses individually.
// As a result we have to implement our own method for exiting
// and other commands (e.g. ctrl+c & ctrl+z)
// $FlowIgnore[method-unbinding]
// $FlowFixMe[sketchy-null-mixed]
if (!process.stdin.setRawMode) {
logger.debug('Watch mode is not supported in this environment');
return;
if (process.stdin.isTTY !== true) {
logger.debug('Interactive mode is not supported in this environment');
}

readline.emitKeypressEvents(process.stdin);

// $FlowIgnore[prop-missing]
process.stdin.setRawMode(true);

// We have no way of knowing when the dependency graph is done loading
// except by hooking into stdout itself. We want to print instructions
// right after its done loading.
const restore: () => void = hookStdout((output: string) => {
// TODO(T160391951) Replace this string check with a suitable integration point
// in Metro
if (output.includes('Fast - Scalable - Integrated')) {
printWatchModeInstructions();
restore();
}
});

const onPressAsync = async (key: string) => {
switch (key) {
case 'r':
Expand All @@ -83,15 +53,15 @@ function enableWatchMode(
execa('npx', [
'react-native',
'run-ios',
...(ctx.project.ios?.watchModeCommandParams ?? []),
...(cliConfig.project.ios?.watchModeCommandParams ?? []),
]).stdout?.pipe(process.stdout);
break;
case 'a':
logger.info('Opening app on Android...');
execa('npx', [
'react-native',
'run-android',
...(ctx.project.android?.watchModeCommandParams ?? []),
...(cliConfig.project.android?.watchModeCommandParams ?? []),
]).stdout?.pipe(process.stdout);
break;
case CTRL_Z:
Expand All @@ -106,6 +76,13 @@ function enableWatchMode(
const listener = keyPressHandler.createInteractionListener();
addInteractionListener(listener);
keyPressHandler.startInterceptingKeyStrokes();
}

export default enableWatchMode;
logger.log(
[
`${chalk.bold('r')} - reload app`,
`${chalk.bold('d')} - open Dev Menu`,
`${chalk.bold('r')} - run on iOS`,
`${chalk.bold('a')} - run on Android`,
].join('\n'),
);
}
39 changes: 19 additions & 20 deletions packages/community-cli-plugin/src/commands/start/runServer.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import {
} from '@react-native-community/cli-tools';

import loadMetroConfig from '../../utils/loadMetroConfig';
import enableWatchMode from './watchMode';
import attachKeyHandlers from './attachKeyHandlers';

export type Args = {
assetPlugins?: string[],
Expand Down Expand Up @@ -91,21 +91,6 @@ async function runServer(_argv: Array<string>, ctx: Config, args: Args) {
sourceExts: args.sourceExts,
});

let reportEvent: (event: TerminalReportableEvent) => void;
const terminal = new Terminal(process.stdout);
const ReporterImpl = getReporterImpl(args.customLogReporterPath);
const terminalReporter = new ReporterImpl(terminal);
const reporter: Reporter = {
update(event: TerminalReportableEvent) {
terminalReporter.update(event);
if (reportEvent) {
reportEvent(event);
}
},
};
// $FlowIgnore[cannot-write] Assigning to readonly property
metroConfig.reporter = reporter;

if (args.assetPlugins) {
// $FlowIgnore[cannot-write] Assigning to readonly property
metroConfig.transformer.assetPlugins = args.assetPlugins.map(plugin =>
Expand Down Expand Up @@ -137,6 +122,24 @@ async function runServer(_argv: Array<string>, ctx: Config, args: Args) {
return middleware.use(metroMiddleware);
};

let reportEvent: (event: TerminalReportableEvent) => void;
const terminal = new Terminal(process.stdout);
const ReporterImpl = getReporterImpl(args.customLogReporterPath);
const terminalReporter = new ReporterImpl(terminal);
const reporter: Reporter = {
update(event: TerminalReportableEvent) {
terminalReporter.update(event);
if (reportEvent) {
reportEvent(event);
}
if (args.interactive && event.type === 'dep_graph_loaded') {
attachKeyHandlers(ctx, messageSocketEndpoint);
}
},
};
// $FlowIgnore[cannot-write] Assigning to readonly property
metroConfig.reporter = reporter;

const serverInstance = await Metro.runServer(metroConfig, {
host: args.host,
secure: args.https,
Expand All @@ -148,10 +151,6 @@ async function runServer(_argv: Array<string>, ctx: Config, args: Args) {

reportEvent = eventsSocketEndpoint.reportEvent;

if (args.interactive) {
enableWatchMode(messageSocketEndpoint, ctx);
}

// In Node 8, the default keep-alive for an HTTP connection is 5 seconds. In
// early versions of Node 8, this was implemented in a buggy way which caused
// some HTTP responses (like those containing large JS bundles) to be
Expand Down

0 comments on commit 202a180

Please sign in to comment.