@react-native/community-cli-plugin 0.73.0 → 0.73.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/README.md +7 -3
  2. package/dist/commands/bundle/assetCatalogIOS.js.flow +9 -57
  3. package/dist/commands/bundle/assetPathUtils.js.flow +12 -66
  4. package/dist/commands/bundle/buildBundle.js +16 -7
  5. package/dist/commands/bundle/buildBundle.js.flow +39 -95
  6. package/dist/commands/bundle/filterPlatformAssetScales.js.flow +5 -33
  7. package/dist/commands/bundle/getAssetDestPathAndroid.js.flow +7 -14
  8. package/dist/commands/bundle/getAssetDestPathIOS.js.flow +7 -16
  9. package/dist/commands/bundle/index.js +124 -0
  10. package/dist/commands/bundle/index.js.flow +18 -0
  11. package/dist/commands/bundle/saveAssets.js +1 -1
  12. package/dist/commands/bundle/saveAssets.js.flow +6 -124
  13. package/dist/commands/{bundle/ramBundle.js → ram-bundle/index.js} +17 -19
  14. package/dist/commands/ram-bundle/index.js.flow +15 -0
  15. package/dist/commands/start/attachKeyHandlers.js +109 -0
  16. package/dist/commands/start/attachKeyHandlers.js.flow +22 -0
  17. package/dist/commands/start/index.js +3 -8
  18. package/dist/commands/start/index.js.flow +6 -85
  19. package/dist/commands/start/runServer.js +82 -32
  20. package/dist/commands/start/runServer.js.flow +9 -127
  21. package/dist/index.flow.js +2 -2
  22. package/dist/index.flow.js.flow +5 -5
  23. package/dist/index.js.flow +1 -9
  24. package/dist/utils/KeyPressHandler.js +91 -0
  25. package/dist/utils/KeyPressHandler.js.flow +22 -0
  26. package/dist/utils/isDevServerRunning.js +74 -0
  27. package/dist/utils/isDevServerRunning.js.flow +27 -0
  28. package/dist/utils/loadMetroConfig.js +6 -7
  29. package/dist/utils/loadMetroConfig.js.flow +10 -102
  30. package/dist/utils/metroPlatformResolver.js.flow +4 -18
  31. package/package.json +11 -9
  32. package/dist/commands/bundle/bundle.js +0 -44
  33. package/dist/commands/bundle/bundle.js.flow +0 -37
  34. package/dist/commands/bundle/bundleCommandLineArgs.js +0 -116
  35. package/dist/commands/bundle/bundleCommandLineArgs.js.flow +0 -129
  36. package/dist/commands/bundle/ramBundle.js.flow +0 -43
  37. package/dist/commands/start/startServerInNewWindow.js +0 -132
  38. package/dist/commands/start/startServerInNewWindow.js.flow +0 -125
  39. package/dist/commands/start/watchMode.js +0 -95
  40. package/dist/commands/start/watchMode.js.flow +0 -101
  41. package/launchPackager.bat +0 -7
  42. package/launchPackager.command +0 -10
@@ -32,7 +32,7 @@ function _interopRequireDefault(obj) {
32
32
  */
33
33
 
34
34
  async function saveAssets(assets, platform, assetsDest, assetCatalogDest) {
35
- if (!assetsDest) {
35
+ if (assetsDest == null) {
36
36
  _cliTools.logger.warn("Assets destination folder is not set, skipping...");
37
37
  return;
38
38
  }
@@ -4,136 +4,18 @@
4
4
  * This source code is licensed under the MIT license found in the
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  *
7
- * @flow
7
+ * @flow strict-local
8
8
  * @format
9
9
  * @oncall react_native
10
10
  */
11
11
 
12
- import type {AssetData} from 'metro/src/Assets';
12
+ import type { AssetData } from "metro/src/Assets";
13
13
 
14
- import {logger} from '@react-native-community/cli-tools';
15
- import fs from 'fs';
16
- import path from 'path';
17
- import {
18
- cleanAssetCatalog,
19
- getImageSet,
20
- isCatalogAsset,
21
- writeImageSet,
22
- } from './assetCatalogIOS';
23
- import filterPlatformAssetScales from './filterPlatformAssetScales';
24
- import getAssetDestPathAndroid from './getAssetDestPathAndroid';
25
- import getAssetDestPathIOS from './getAssetDestPathIOS';
26
-
27
- type CopiedFiles = {
28
- [src: string]: string,
29
- };
30
-
31
- async function saveAssets(
14
+ declare function saveAssets(
32
15
  assets: $ReadOnlyArray<AssetData>,
33
16
  platform: string,
34
17
  assetsDest?: string,
35
- assetCatalogDest?: string,
36
- ): Promise<void> {
37
- if (!assetsDest) {
38
- logger.warn('Assets destination folder is not set, skipping...');
39
- return;
40
- }
41
-
42
- const filesToCopy: CopiedFiles = {};
43
-
44
- const getAssetDestPath =
45
- platform === 'android' ? getAssetDestPathAndroid : getAssetDestPathIOS;
46
-
47
- const addAssetToCopy = (asset: AssetData) => {
48
- const validScales = new Set(
49
- filterPlatformAssetScales(platform, asset.scales),
50
- );
51
-
52
- asset.scales.forEach((scale, idx) => {
53
- if (!validScales.has(scale)) {
54
- return;
55
- }
56
- const src = asset.files[idx];
57
- const dest = path.join(assetsDest, getAssetDestPath(asset, scale));
58
- filesToCopy[src] = dest;
59
- });
60
- };
61
-
62
- if (platform === 'ios' && assetCatalogDest != null) {
63
- // Use iOS Asset Catalog for images. This will allow Apple app thinning to
64
- // remove unused scales from the optimized bundle.
65
- const catalogDir = path.join(assetCatalogDest, 'RNAssets.xcassets');
66
- if (!fs.existsSync(catalogDir)) {
67
- logger.error(
68
- `Could not find asset catalog 'RNAssets.xcassets' in ${assetCatalogDest}. Make sure to create it if it does not exist.`,
69
- );
70
- return;
71
- }
72
-
73
- logger.info('Adding images to asset catalog', catalogDir);
74
- cleanAssetCatalog(catalogDir);
75
- for (const asset of assets) {
76
- if (isCatalogAsset(asset)) {
77
- const imageSet = getImageSet(
78
- catalogDir,
79
- asset,
80
- filterPlatformAssetScales(platform, asset.scales),
81
- );
82
- writeImageSet(imageSet);
83
- } else {
84
- addAssetToCopy(asset);
85
- }
86
- }
87
- logger.info('Done adding images to asset catalog');
88
- } else {
89
- assets.forEach(addAssetToCopy);
90
- }
91
-
92
- return copyAll(filesToCopy);
93
- }
94
-
95
- function copyAll(filesToCopy: CopiedFiles) {
96
- const queue = Object.keys(filesToCopy);
97
- if (queue.length === 0) {
98
- return Promise.resolve();
99
- }
100
-
101
- logger.info(`Copying ${queue.length} asset files`);
102
- return new Promise<void>((resolve, reject) => {
103
- const copyNext = (error?: Error) => {
104
- if (error) {
105
- reject(error);
106
- return;
107
- }
108
- if (queue.length === 0) {
109
- logger.info('Done copying assets');
110
- resolve();
111
- } else {
112
- // queue.length === 0 is checked in previous branch, so this is string
113
- const src = queue.shift();
114
- const dest = filesToCopy[src];
115
- copy(src, dest, copyNext);
116
- }
117
- };
118
- copyNext();
119
- });
120
- }
121
-
122
- function copy(
123
- src: string,
124
- dest: string,
125
- callback: (error: Error) => void,
126
- ): void {
127
- const destDir = path.dirname(dest);
128
- fs.mkdir(destDir, {recursive: true}, (err?) => {
129
- if (err) {
130
- callback(err);
131
- return;
132
- }
133
- fs.createReadStream(src)
134
- .pipe(fs.createWriteStream(dest))
135
- .on('finish', callback);
136
- });
137
- }
18
+ assetCatalogDest?: string
19
+ ): Promise<void>;
138
20
 
139
- export default saveAssets;
21
+ declare export default saveAssets;
@@ -4,14 +4,11 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true,
5
5
  });
6
6
  exports.default = void 0;
7
- exports.ramBundle = ramBundle;
8
7
  var _RamBundle = _interopRequireDefault(
9
8
  require("metro/src/shared/output/RamBundle")
10
9
  );
11
- var _bundle = require("./bundle");
12
- var _bundleCommandLineArgs = _interopRequireDefault(
13
- require("./bundleCommandLineArgs")
14
- );
10
+ var _bundle = _interopRequireDefault(require("../bundle"));
11
+ var _buildBundle = _interopRequireDefault(require("../bundle/buildBundle"));
15
12
  function _interopRequireDefault(obj) {
16
13
  return obj && obj.__esModule ? obj : { default: obj };
17
14
  }
@@ -26,22 +23,23 @@ function _interopRequireDefault(obj) {
26
23
  * @oncall react_native
27
24
  */
28
25
 
29
- /**
30
- * Builds the bundle starting to look for dependencies at the given entry path.
31
- */
32
- function ramBundle(argv, config, args) {
33
- return (0, _bundle.bundleWithOutput)(argv, config, args, _RamBundle.default);
34
- }
35
- var _default = {
26
+ const ramBundleCommand = {
36
27
  name: "ram-bundle",
37
28
  description:
38
29
  "Build the RAM bundle for the provided JavaScript entry file. See https://reactnative.dev/docs/ram-bundles-inline-requires.",
39
- func: ramBundle,
40
- options: _bundleCommandLineArgs.default.concat({
41
- name: "--indexed-ram-bundle",
42
- description:
43
- 'Force the "Indexed RAM" bundle file format, even when building for android',
44
- default: false,
45
- }),
30
+ func: (argv, config, args) => {
31
+ return (0, _buildBundle.default)(argv, config, args, _RamBundle.default);
32
+ },
33
+ options: [
34
+ // $FlowFixMe[incompatible-type] options is nonnull
35
+ ..._bundle.default.options,
36
+ {
37
+ name: "--indexed-ram-bundle",
38
+ description:
39
+ 'Force the "Indexed RAM" bundle file format, even when building for android',
40
+ default: false,
41
+ },
42
+ ],
46
43
  };
44
+ var _default = ramBundleCommand;
47
45
  exports.default = _default;
@@ -0,0 +1,15 @@
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 { Command } from "@react-native-community/cli-types";
13
+ declare const ramBundleCommand: Command;
14
+
15
+ declare export default ramBundleCommand;
@@ -0,0 +1,109 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true,
5
+ });
6
+ exports.default = attachKeyHandlers;
7
+ var _cliTools = require("@react-native-community/cli-tools");
8
+ var _chalk = _interopRequireDefault(require("chalk"));
9
+ var _execa = _interopRequireDefault(require("execa"));
10
+ var _nodeFetch = _interopRequireDefault(require("node-fetch"));
11
+ var _readline = _interopRequireDefault(require("readline"));
12
+ var _KeyPressHandler = require("../../utils/KeyPressHandler");
13
+ function _interopRequireDefault(obj) {
14
+ return obj && obj.__esModule ? obj : { default: obj };
15
+ }
16
+ /**
17
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
18
+ *
19
+ * This source code is licensed under the MIT license found in the
20
+ * LICENSE file in the root directory of this source tree.
21
+ *
22
+ *
23
+ * @format
24
+ * @oncall react_native
25
+ */
26
+
27
+ const CTRL_C = "\u0003";
28
+ const CTRL_D = "\u0004";
29
+ function attachKeyHandlers({
30
+ cliConfig,
31
+ serverInstance,
32
+ devServerUrl,
33
+ messageSocket,
34
+ }) {
35
+ if (process.stdin.isTTY !== true) {
36
+ _cliTools.logger.debug(
37
+ "Interactive mode is not supported in this environment"
38
+ );
39
+ return;
40
+ }
41
+ _readline.default.emitKeypressEvents(process.stdin);
42
+ // $FlowIgnore[prop-missing]
43
+ process.stdin.setRawMode(true);
44
+ const execaOptions = {
45
+ env: {
46
+ FORCE_COLOR: _chalk.default.supportsColor ? "true" : "false",
47
+ },
48
+ };
49
+ const keyPressHandler = new _KeyPressHandler.KeyPressHandler(async (key) => {
50
+ switch (key) {
51
+ case "r":
52
+ messageSocket.broadcast("reload", null);
53
+ _cliTools.logger.info("Reloading connected app(s)...");
54
+ break;
55
+ case "d":
56
+ messageSocket.broadcast("devMenu", null);
57
+ _cliTools.logger.info("Opening Dev Menu...");
58
+ break;
59
+ case "i":
60
+ _cliTools.logger.info("Opening app on iOS...");
61
+ (0, _execa.default)(
62
+ "npx",
63
+ [
64
+ "react-native",
65
+ "run-ios",
66
+ ...(cliConfig.project.ios?.watchModeCommandParams ?? []),
67
+ ],
68
+ execaOptions
69
+ ).stdout?.pipe(process.stdout);
70
+ break;
71
+ case "a":
72
+ _cliTools.logger.info("Opening app on Android...");
73
+ (0, _execa.default)(
74
+ "npx",
75
+ [
76
+ "react-native",
77
+ "run-android",
78
+ ...(cliConfig.project.android?.watchModeCommandParams ?? []),
79
+ ],
80
+ execaOptions
81
+ ).stdout?.pipe(process.stdout);
82
+ break;
83
+ case "j":
84
+ await (0, _nodeFetch.default)(devServerUrl + "/open-debugger", {
85
+ method: "POST",
86
+ });
87
+ break;
88
+ case CTRL_C:
89
+ case CTRL_D:
90
+ _cliTools.logger.info("Stopping server");
91
+ listener?.({
92
+ pause: true,
93
+ });
94
+ serverInstance.close(() => {
95
+ process.emit("SIGINT");
96
+ process.exit();
97
+ });
98
+ }
99
+ });
100
+ const listener = keyPressHandler.createInteractionListener();
101
+ keyPressHandler.startInterceptingKeyStrokes();
102
+ _cliTools.logger.log(`
103
+ ${_chalk.default.bold("i")} - run on iOS
104
+ ${_chalk.default.bold("a")} - run on Android
105
+ ${_chalk.default.bold("d")} - open Dev Menu
106
+ ${_chalk.default.bold("j")} - open debugger
107
+ ${_chalk.default.bold("r")} - reload app
108
+ `);
109
+ }
@@ -0,0 +1,22 @@
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 { Config } from "@react-native-community/cli-types";
13
+
14
+ declare export default function attachKeyHandlers({
15
+ cliConfig: Config,
16
+ devServerUrl: string,
17
+ serverInstance: http$Server | https$Server,
18
+ messageSocket: $ReadOnly<{
19
+ broadcast: (type: string, params?: Record<string, mixed> | null) => void,
20
+ ...
21
+ }>,
22
+ }): void;
@@ -4,15 +4,8 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true,
5
5
  });
6
6
  exports.default = void 0;
7
- Object.defineProperty(exports, "startServerInNewWindow", {
8
- enumerable: true,
9
- get: function () {
10
- return _startServerInNewWindow.startServerInNewWindow;
11
- },
12
- });
13
7
  var _path = _interopRequireDefault(require("path"));
14
8
  var _runServer = _interopRequireDefault(require("./runServer"));
15
- var _startServerInNewWindow = require("./startServerInNewWindow");
16
9
  function _interopRequireDefault(obj) {
17
10
  return obj && obj.__esModule ? obj : { default: obj };
18
11
  }
@@ -26,7 +19,8 @@ function _interopRequireDefault(obj) {
26
19
  * @format
27
20
  * @oncall react_native
28
21
  */
29
- var _default = {
22
+
23
+ const startCommand = {
30
24
  name: "start",
31
25
  func: _runServer.default,
32
26
  description: "Start the React Native development server.",
@@ -107,4 +101,5 @@ var _default = {
107
101
  },
108
102
  ],
109
103
  };
104
+ var _default = startCommand;
110
105
  exports.default = _default;
@@ -4,94 +4,15 @@
4
4
  * This source code is licensed under the MIT license found in the
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  *
7
- * @flow
7
+ * @flow strict-local
8
8
  * @format
9
9
  * @oncall react_native
10
10
  */
11
11
 
12
- import path from 'path';
13
- import runServer from './runServer';
12
+ import type { Command } from "@react-native-community/cli-types";
14
13
 
15
- export default {
16
- name: 'start',
17
- func: runServer,
18
- description: 'Start the React Native development server.',
19
- options: [
20
- {
21
- name: '--port <number>',
22
- parse: Number,
23
- },
24
- {
25
- name: '--host <string>',
26
- default: '',
27
- },
28
- {
29
- name: '--projectRoot <path>',
30
- description: 'Path to a custom project root',
31
- parse: (val: string): string => path.resolve(val),
32
- },
33
- {
34
- name: '--watchFolders <list>',
35
- description:
36
- 'Specify any additional folders to be added to the watch list',
37
- parse: (val: string): Array<string> =>
38
- val.split(',').map((folder: string) => path.resolve(folder)),
39
- },
40
- {
41
- name: '--assetPlugins <list>',
42
- description:
43
- 'Specify any additional asset plugins to be used by the packager by full filepath',
44
- parse: (val: string): Array<string> => val.split(','),
45
- },
46
- {
47
- name: '--sourceExts <list>',
48
- description:
49
- 'Specify any additional source extensions to be used by the packager',
50
- parse: (val: string): Array<string> => val.split(','),
51
- },
52
- {
53
- name: '--max-workers <number>',
54
- description:
55
- 'Specifies the maximum number of workers the worker-pool ' +
56
- 'will spawn for transforming files. This defaults to the number of the ' +
57
- 'cores available on your machine.',
58
- parse: (workers: string): number => Number(workers),
59
- },
60
- {
61
- name: '--transformer <string>',
62
- description: 'Specify a custom transformer to be used',
63
- },
64
- {
65
- name: '--reset-cache, --resetCache',
66
- description: 'Removes cached files',
67
- },
68
- {
69
- name: '--custom-log-reporter-path, --customLogReporterPath <string>',
70
- description:
71
- 'Path to a JavaScript file that exports a log reporter as a replacement for TerminalReporter',
72
- },
73
- {
74
- name: '--https',
75
- description: 'Enables https connections to the server',
76
- },
77
- {
78
- name: '--key <path>',
79
- description: 'Path to custom SSL key',
80
- },
81
- {
82
- name: '--cert <path>',
83
- description: 'Path to custom SSL cert',
84
- },
85
- {
86
- name: '--config <string>',
87
- description: 'Path to the CLI configuration file',
88
- parse: (val: string): string => path.resolve(val),
89
- },
90
- {
91
- name: '--no-interactive',
92
- description: 'Disables interactive mode',
93
- },
94
- ],
95
- };
14
+ export type { StartCommandArgs } from "./runServer";
96
15
 
97
- export {startServerInNewWindow} from './startServerInNewWindow';
16
+ declare const startCommand: Command;
17
+
18
+ declare export default startCommand;
@@ -4,15 +4,20 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true,
5
5
  });
6
6
  exports.default = void 0;
7
+ var _chalk = _interopRequireDefault(require("chalk"));
7
8
  var _metro = _interopRequireDefault(require("metro"));
8
9
  var _metroCore = require("metro-core");
9
10
  var _path = _interopRequireDefault(require("path"));
11
+ var _devMiddleware = require("@react-native/dev-middleware");
10
12
  var _cliServerApi = require("@react-native-community/cli-server-api");
13
+ var _cliTools = require("@react-native-community/cli-tools");
14
+ var _isDevServerRunning = _interopRequireDefault(
15
+ require("../../utils/isDevServerRunning")
16
+ );
11
17
  var _loadMetroConfig = _interopRequireDefault(
12
18
  require("../../utils/loadMetroConfig")
13
19
  );
14
- var _cliTools = require("@react-native-community/cli-tools");
15
- var _watchMode = _interopRequireDefault(require("./watchMode"));
20
+ var _attachKeyHandlers = _interopRequireDefault(require("./attachKeyHandlers"));
16
21
  function _interopRequireDefault(obj) {
17
22
  return obj && obj.__esModule ? obj : { default: obj };
18
23
  }
@@ -28,27 +33,45 @@ function _interopRequireDefault(obj) {
28
33
  */
29
34
 
30
35
  async function runServer(_argv, ctx, args) {
31
- let reportEvent;
32
- const terminal = new _metroCore.Terminal(process.stdout);
33
- const ReporterImpl = getReporterImpl(args.customLogReporterPath);
34
- const terminalReporter = new ReporterImpl(terminal);
35
36
  const metroConfig = await (0, _loadMetroConfig.default)(ctx, {
36
37
  config: args.config,
37
38
  maxWorkers: args.maxWorkers,
38
- port: args.port,
39
+ port: args.port ?? 8081,
39
40
  resetCache: args.resetCache,
40
41
  watchFolders: args.watchFolders,
41
42
  projectRoot: args.projectRoot,
42
43
  sourceExts: args.sourceExts,
43
- reporter: {
44
- update(event) {
45
- terminalReporter.update(event);
46
- if (reportEvent) {
47
- reportEvent(event);
48
- }
49
- },
50
- },
51
44
  });
45
+ const host = args.host?.length ? args.host : "localhost";
46
+ const {
47
+ projectRoot,
48
+ server: { port },
49
+ watchFolders,
50
+ } = metroConfig;
51
+ const scheme = args.https === true ? "https" : "http";
52
+ const devServerUrl = `${scheme}://${host}:${port}`;
53
+ _cliTools.logger.info(`Welcome to React Native v${ctx.reactNativeVersion}`);
54
+ const serverStatus = await (0, _isDevServerRunning.default)(
55
+ scheme,
56
+ host,
57
+ port,
58
+ projectRoot
59
+ );
60
+ if (serverStatus === "matched_server_running") {
61
+ _cliTools.logger.info(
62
+ `A dev server is already running for this project on port ${port}. Exiting.`
63
+ );
64
+ return;
65
+ } else if (serverStatus === "port_taken") {
66
+ _cliTools.logger.error(
67
+ `Another process is running on port ${port}. Please terminate this ` +
68
+ 'process and try again, or use another port with "--port".'
69
+ );
70
+ return;
71
+ }
72
+ _cliTools.logger.info(
73
+ `Starting dev server on port ${_chalk.default.bold(String(port))}...`
74
+ );
52
75
  if (args.assetPlugins) {
53
76
  // $FlowIgnore[cannot-write] Assigning to readonly property
54
77
  metroConfig.transformer.assetPlugins = args.assetPlugins.map((plugin) =>
@@ -56,36 +79,63 @@ async function runServer(_argv, ctx, args) {
56
79
  );
57
80
  }
58
81
  const {
59
- middleware,
60
- websocketEndpoints,
82
+ middleware: communityMiddleware,
83
+ websocketEndpoints: communityWebsocketEndpoints,
61
84
  messageSocketEndpoint,
62
85
  eventsSocketEndpoint,
63
86
  } = (0, _cliServerApi.createDevServerMiddleware)({
64
- host: args.host,
65
- port: metroConfig.server.port,
66
- watchFolders: metroConfig.watchFolders,
87
+ host,
88
+ port,
89
+ watchFolders,
90
+ });
91
+ const { middleware, websocketEndpoints } = (0,
92
+ _devMiddleware.createDevMiddleware)({
93
+ projectRoot,
94
+ serverBaseUrl: devServerUrl,
95
+ logger: _cliTools.logger,
96
+ unstable_experiments: {
97
+ // NOTE: Only affects the /open-debugger endpoint
98
+ enableCustomDebuggerFrontend: true,
99
+ },
67
100
  });
68
- middleware.use(_cliServerApi.indexPageMiddleware);
69
- const customEnhanceMiddleware = metroConfig.server.enhanceMiddleware;
101
+ let reportEvent;
102
+ const terminal = new _metroCore.Terminal(process.stdout);
103
+ const ReporterImpl = getReporterImpl(args.customLogReporterPath);
104
+ const terminalReporter = new ReporterImpl(terminal);
70
105
  // $FlowIgnore[cannot-write] Assigning to readonly property
71
- metroConfig.server.enhanceMiddleware = (metroMiddleware, server) => {
72
- if (customEnhanceMiddleware) {
73
- metroMiddleware = customEnhanceMiddleware(metroMiddleware, server);
74
- }
75
- return middleware.use(metroMiddleware);
106
+ metroConfig.reporter = {
107
+ update(event) {
108
+ terminalReporter.update(event);
109
+ if (reportEvent) {
110
+ reportEvent(event);
111
+ }
112
+ if (args.interactive && event.type === "initialize_done") {
113
+ _cliTools.logger.info("Dev server ready");
114
+ (0, _attachKeyHandlers.default)({
115
+ cliConfig: ctx,
116
+ devServerUrl,
117
+ serverInstance,
118
+ messageSocket: messageSocketEndpoint,
119
+ });
120
+ }
121
+ },
76
122
  };
77
123
  const serverInstance = await _metro.default.runServer(metroConfig, {
78
124
  host: args.host,
79
125
  secure: args.https,
80
126
  secureCert: args.cert,
81
127
  secureKey: args.key,
82
- // $FlowFixMe[incompatible-call] Incompatibly defined WebSocketServer type
83
- websocketEndpoints,
128
+ unstable_extraMiddleware: [
129
+ communityMiddleware,
130
+ _cliServerApi.indexPageMiddleware,
131
+ middleware,
132
+ ],
133
+ websocketEndpoints: {
134
+ ...communityWebsocketEndpoints,
135
+ ...websocketEndpoints,
136
+ },
84
137
  });
85
138
  reportEvent = eventsSocketEndpoint.reportEvent;
86
- if (args.interactive) {
87
- (0, _watchMode.default)(messageSocketEndpoint, ctx);
88
- }
89
139
 
90
140
  // In Node 8, the default keep-alive for an HTTP connection is 5 seconds. In
91
141
  // early versions of Node 8, this was implemented in a buggy way which caused