From a7f279f14a400c7b02e9db263f39bce5fd3934f6 Mon Sep 17 00:00:00 2001 From: Alex Hunt Date: Mon, 21 Aug 2023 04:12:39 -0700 Subject: [PATCH] Refactor CLI command entry points (#39075) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/39075 Small refactor: reorganise command entry points and types into a consistent pattern. Changelog: [Internal] Reviewed By: blakef Differential Revision: D48433284 fbshipit-source-id: 94fe81c37469e2790519a8e058987e93cc9c0ea6 --- .../src/commands/bundle/buildBundle.js | 45 ++++-- .../src/commands/bundle/bundle.js | 38 ------ .../commands/bundle/bundleCommandLineArgs.js | 129 ------------------ .../src/commands/bundle/index.js | 120 ++++++++++++++++ .../ramBundle.js => ram-bundle/index.js} | 32 ++--- .../src/commands/start/index.js | 8 +- .../src/commands/start/runServer.js | 8 +- .../community-cli-plugin/src/index.flow.js | 4 +- 8 files changed, 182 insertions(+), 202 deletions(-) delete mode 100644 packages/community-cli-plugin/src/commands/bundle/bundle.js delete mode 100644 packages/community-cli-plugin/src/commands/bundle/bundleCommandLineArgs.js create mode 100644 packages/community-cli-plugin/src/commands/bundle/index.js rename packages/community-cli-plugin/src/commands/{bundle/ramBundle.js => ram-bundle/index.js} (53%) diff --git a/packages/community-cli-plugin/src/commands/bundle/buildBundle.js b/packages/community-cli-plugin/src/commands/bundle/buildBundle.js index ca265c1a1c74ed..525f46748bb822 100644 --- a/packages/community-cli-plugin/src/commands/bundle/buildBundle.js +++ b/packages/community-cli-plugin/src/commands/bundle/buildBundle.js @@ -12,20 +12,43 @@ import type {Config} from '@react-native-community/cli-types'; import type {RequestOptions} from 'metro/src/shared/types.flow'; import type {ConfigT} from 'metro-config'; -import type {CommandLineArgs} from './bundleCommandLineArgs'; import Server from 'metro/src/Server'; -const outputBundle = require('metro/src/shared/output/bundle'); +import metroBundle from 'metro/src/shared/output/bundle'; +import metroRamBundle from 'metro/src/shared/output/RamBundle'; import path from 'path'; import chalk from 'chalk'; import saveAssets from './saveAssets'; -import {default as loadMetroConfig} from '../../utils/loadMetroConfig'; +import loadMetroConfig from '../../utils/loadMetroConfig'; import {logger} from '@react-native-community/cli-tools'; +export type BundleCommandArgs = { + assetsDest?: string, + assetCatalogDest?: string, + entryFile: string, + resetCache: boolean, + resetGlobalCache: boolean, + transformer?: string, + minify?: boolean, + config?: string, + platform: string, + dev: boolean, + bundleOutput: string, + bundleEncoding?: 'utf8' | 'utf16le' | 'ascii', + maxWorkers?: number, + sourcemapOutput?: string, + sourcemapSourcesRoot?: string, + sourcemapUseAbsolutePath: boolean, + verbose: boolean, + unstableTransformProfile: string, + indexedRamBundle?: boolean, +}; + async function buildBundle( - args: CommandLineArgs, + _argv: Array, ctx: Config, - output: typeof outputBundle = outputBundle, + args: BundleCommandArgs, + bundleImpl: typeof metroBundle | typeof metroRamBundle = metroBundle, ): Promise { const config = await loadMetroConfig(ctx, { maxWorkers: args.maxWorkers, @@ -33,13 +56,13 @@ async function buildBundle( config: args.config, }); - return buildBundleWithConfig(args, config, output); + return buildBundleWithConfig(args, config, bundleImpl); } async function buildBundleWithConfig( - args: CommandLineArgs, + args: BundleCommandArgs, config: ConfigT, - output: typeof outputBundle = outputBundle, + bundleImpl: typeof metroBundle | typeof metroRamBundle = metroBundle, ): Promise { if (config.resolver.platforms.indexOf(args.platform) === -1) { logger.error( @@ -80,11 +103,13 @@ async function buildBundleWithConfig( const server = new Server(config); try { - const bundle = await output.build(server, requestOpts); + const bundle = await bundleImpl.build(server, requestOpts); // $FlowIgnore[class-object-subtyping] // $FlowIgnore[incompatible-call] - await output.save(bundle, args, logger.info); + // $FlowIgnore[prop-missing] + // $FlowIgnore[incompatible-exact] + await bundleImpl.save(bundle, args, logger.info); // Save the assets of the bundle const outputAssets = await server.getAssets({ diff --git a/packages/community-cli-plugin/src/commands/bundle/bundle.js b/packages/community-cli-plugin/src/commands/bundle/bundle.js deleted file mode 100644 index b81024d2419153..00000000000000 --- a/packages/community-cli-plugin/src/commands/bundle/bundle.js +++ /dev/null @@ -1,38 +0,0 @@ -/** - * 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 {Config} from '@react-native-community/cli-types'; -import type {CommandLineArgs} from './bundleCommandLineArgs'; - -import buildBundle from './buildBundle'; -import bundleCommandLineArgs from './bundleCommandLineArgs'; - -/** - * Builds the bundle starting to look for dependencies at the given entry path. - */ -export function bundleWithOutput( - _: Array, - config: Config, - args: CommandLineArgs, - // $FlowFixMe[unclear-type] untyped metro/src/shared/output/bundle or metro/src/shared/output/RamBundle - output: any, -): Promise { - return buildBundle(args, config, output); -} - -const bundleCommand = { - name: 'bundle', - description: 'Build the bundle for the provided JavaScript entry file.', - func: bundleWithOutput, - options: bundleCommandLineArgs, -}; - -export default bundleCommand; diff --git a/packages/community-cli-plugin/src/commands/bundle/bundleCommandLineArgs.js b/packages/community-cli-plugin/src/commands/bundle/bundleCommandLineArgs.js deleted file mode 100644 index 58f4211b567006..00000000000000 --- a/packages/community-cli-plugin/src/commands/bundle/bundleCommandLineArgs.js +++ /dev/null @@ -1,129 +0,0 @@ -/** - * 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 path from 'path'; - -export interface CommandLineArgs { - assetsDest?: string; - assetCatalogDest?: string; - entryFile: string; - resetCache: boolean; - resetGlobalCache: boolean; - transformer?: string; - minify?: boolean; - config?: string; - platform: string; - dev: boolean; - bundleOutput: string; - bundleEncoding?: 'utf8' | 'utf16le' | 'ascii'; - maxWorkers?: number; - sourcemapOutput?: string; - sourcemapSourcesRoot?: string; - sourcemapUseAbsolutePath: boolean; - verbose: boolean; - unstableTransformProfile: string; -} - -export default [ - { - name: '--entry-file ', - description: - 'Path to the root JS file, either absolute or relative to JS root', - }, - { - name: '--platform ', - description: 'Either "ios" or "android"', - default: 'ios', - }, - { - name: '--transformer ', - description: 'Specify a custom transformer to be used', - }, - { - name: '--dev [boolean]', - description: 'If false, warnings are disabled and the bundle is minified', - parse: (val: string): boolean => val !== 'false', - default: true, - }, - { - name: '--minify [boolean]', - description: - 'Allows overriding whether bundle is minified. This defaults to ' + - 'false if dev is true, and true if dev is false. Disabling minification ' + - 'can be useful for speeding up production builds for testing purposes.', - parse: (val: string): boolean => val !== 'false', - }, - { - name: '--bundle-output ', - description: - 'File name where to store the resulting bundle, ex. /tmp/groups.bundle', - }, - { - name: '--bundle-encoding ', - description: - 'Encoding the bundle should be written in (https://nodejs.org/api/buffer.html#buffer_buffer).', - default: 'utf8', - }, - { - name: '--max-workers ', - description: - 'Specifies the maximum number of workers the worker-pool ' + - 'will spawn for transforming files. This defaults to the number of the ' + - 'cores available on your machine.', - parse: (workers: string): number => Number(workers), - }, - { - name: '--sourcemap-output ', - description: - 'File name where to store the sourcemap file for resulting bundle, ex. /tmp/groups.map', - }, - { - name: '--sourcemap-sources-root ', - description: - "Path to make sourcemap's sources entries relative to, ex. /root/dir", - }, - { - name: '--sourcemap-use-absolute-path', - description: 'Report SourceMapURL using its full path', - default: false, - }, - { - name: '--assets-dest ', - description: - 'Directory name where to store assets referenced in the bundle', - }, - { - name: '--unstable-transform-profile ', - description: - 'Experimental, transform JS for a specific JS engine. Currently supported: hermes, hermes-canary, default', - default: 'default', - }, - { - name: '--asset-catalog-dest [string]', - description: 'Path where to create an iOS Asset Catalog for images', - }, - { - name: '--reset-cache', - description: 'Removes cached files', - default: false, - }, - { - name: '--read-global-cache', - description: - 'Try to fetch transformed JS code from the global cache, if configured.', - default: false, - }, - { - name: '--config ', - description: 'Path to the CLI configuration file', - parse: (val: string): string => path.resolve(val), - }, -]; diff --git a/packages/community-cli-plugin/src/commands/bundle/index.js b/packages/community-cli-plugin/src/commands/bundle/index.js new file mode 100644 index 00000000000000..6a480c4e333aba --- /dev/null +++ b/packages/community-cli-plugin/src/commands/bundle/index.js @@ -0,0 +1,120 @@ +/** + * 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 {Command} from '@react-native-community/cli-types'; + +import path from 'path'; +import buildBundle from './buildBundle'; + +export type {BundleCommandArgs} from './buildBundle'; + +const bundleCommand: Command = { + name: 'bundle', + description: 'Build the bundle for the provided JavaScript entry file.', + func: buildBundle, + options: [ + { + name: '--entry-file ', + description: + 'Path to the root JS file, either absolute or relative to JS root', + }, + { + name: '--platform ', + description: 'Either "ios" or "android"', + default: 'ios', + }, + { + name: '--transformer ', + description: 'Specify a custom transformer to be used', + }, + { + name: '--dev [boolean]', + description: 'If false, warnings are disabled and the bundle is minified', + parse: (val: string): boolean => val !== 'false', + default: true, + }, + { + name: '--minify [boolean]', + description: + 'Allows overriding whether bundle is minified. This defaults to ' + + 'false if dev is true, and true if dev is false. Disabling minification ' + + 'can be useful for speeding up production builds for testing purposes.', + parse: (val: string): boolean => val !== 'false', + }, + { + name: '--bundle-output ', + description: + 'File name where to store the resulting bundle, ex. /tmp/groups.bundle', + }, + { + name: '--bundle-encoding ', + description: + 'Encoding the bundle should be written in (https://nodejs.org/api/buffer.html#buffer_buffer).', + default: 'utf8', + }, + { + name: '--max-workers ', + description: + 'Specifies the maximum number of workers the worker-pool ' + + 'will spawn for transforming files. This defaults to the number of the ' + + 'cores available on your machine.', + parse: (workers: string): number => Number(workers), + }, + { + name: '--sourcemap-output ', + description: + 'File name where to store the sourcemap file for resulting bundle, ex. /tmp/groups.map', + }, + { + name: '--sourcemap-sources-root ', + description: + "Path to make sourcemap's sources entries relative to, ex. /root/dir", + }, + { + name: '--sourcemap-use-absolute-path', + description: 'Report SourceMapURL using its full path', + default: false, + }, + { + name: '--assets-dest ', + description: + 'Directory name where to store assets referenced in the bundle', + }, + { + name: '--unstable-transform-profile ', + description: + 'Experimental, transform JS for a specific JS engine. Currently supported: hermes, hermes-canary, default', + default: 'default', + }, + { + name: '--asset-catalog-dest [string]', + description: 'Path where to create an iOS Asset Catalog for images', + }, + { + name: '--reset-cache', + description: 'Removes cached files', + default: false, + }, + { + name: '--read-global-cache', + description: + 'Try to fetch transformed JS code from the global cache, if configured.', + default: false, + }, + { + name: '--config ', + description: 'Path to the CLI configuration file', + parse: (val: string): string => path.resolve(val), + }, + ], +}; + +export default bundleCommand; diff --git a/packages/community-cli-plugin/src/commands/bundle/ramBundle.js b/packages/community-cli-plugin/src/commands/ram-bundle/index.js similarity index 53% rename from packages/community-cli-plugin/src/commands/bundle/ramBundle.js rename to packages/community-cli-plugin/src/commands/ram-bundle/index.js index eea8404f5612e6..1cf978ffc8d4e8 100644 --- a/packages/community-cli-plugin/src/commands/bundle/ramBundle.js +++ b/packages/community-cli-plugin/src/commands/ram-bundle/index.js @@ -10,30 +10,22 @@ */ import type {Command, Config} from '@react-native-community/cli-types'; -import type {CommandLineArgs} from './bundleCommandLineArgs'; +import type {BundleCommandArgs} from '../bundle'; -import outputUnbundle from 'metro/src/shared/output/RamBundle'; -import {bundleWithOutput} from './bundle'; -import bundleCommandLineArgs from './bundleCommandLineArgs'; +import metroRamBundle from 'metro/src/shared/output/RamBundle'; +import bundleCommand from '../bundle'; +import buildBundle from '../bundle/buildBundle'; -/** - * Builds the bundle starting to look for dependencies at the given entry path. - */ -function ramBundle( - argv: Array, - config: Config, - args: CommandLineArgs, -): Promise { - return bundleWithOutput(argv, config, args, outputUnbundle); -} - -export default ({ +const ramBundleCommand: Command = { name: 'ram-bundle', description: 'Build the RAM bundle for the provided JavaScript entry file. See https://reactnative.dev/docs/ram-bundles-inline-requires.', - func: ramBundle, + func: (argv: Array, config: Config, args: BundleCommandArgs) => { + return buildBundle(argv, config, args, metroRamBundle); + }, options: [ - ...bundleCommandLineArgs, + // $FlowFixMe[incompatible-type] options is nonnull + ...bundleCommand.options, { name: '--indexed-ram-bundle', description: @@ -41,6 +33,6 @@ export default ({ default: false, }, ], -}: Command); +}; -export {ramBundle}; +export default ramBundleCommand; diff --git a/packages/community-cli-plugin/src/commands/start/index.js b/packages/community-cli-plugin/src/commands/start/index.js index 573f4e4706292a..8bcf6e1ac4b086 100644 --- a/packages/community-cli-plugin/src/commands/start/index.js +++ b/packages/community-cli-plugin/src/commands/start/index.js @@ -9,10 +9,14 @@ * @oncall react_native */ +import type {Command} from '@react-native-community/cli-types'; + import path from 'path'; import runServer from './runServer'; -export default { +export type {StartCommandArgs} from './runServer'; + +const startCommand: Command = { name: 'start', func: runServer, description: 'Start the React Native development server.', @@ -93,3 +97,5 @@ export default { }, ], }; + +export default startCommand; diff --git a/packages/community-cli-plugin/src/commands/start/runServer.js b/packages/community-cli-plugin/src/commands/start/runServer.js index a6397147f441ff..482d0a6378dcd8 100644 --- a/packages/community-cli-plugin/src/commands/start/runServer.js +++ b/packages/community-cli-plugin/src/commands/start/runServer.js @@ -34,7 +34,7 @@ import { import loadMetroConfig from '../../utils/loadMetroConfig'; import attachKeyHandlers from './attachKeyHandlers'; -export type Args = { +export type StartCommandArgs = { assetPlugins?: string[], cert?: string, customLogReporterPath?: string, @@ -53,7 +53,11 @@ export type Args = { interactive: boolean, }; -async function runServer(_argv: Array, ctx: Config, args: Args) { +async function runServer( + _argv: Array, + ctx: Config, + args: StartCommandArgs, +) { let port = args.port ?? 8081; let packager = true; const packagerStatus = await isPackagerRunning(port); diff --git a/packages/community-cli-plugin/src/index.flow.js b/packages/community-cli-plugin/src/index.flow.js index 5d5e140970a2c8..80adc7e51beb40 100644 --- a/packages/community-cli-plugin/src/index.flow.js +++ b/packages/community-cli-plugin/src/index.flow.js @@ -9,8 +9,8 @@ * @oncall react_native */ -export {default as bundleCommand} from './commands/bundle/bundle'; -export {default as ramBundleCommand} from './commands/bundle/ramBundle'; +export {default as bundleCommand} from './commands/bundle'; +export {default as ramBundleCommand} from './commands/ram-bundle'; export {default as startCommand} from './commands/start'; export {unstable_buildBundleWithConfig} from './commands/bundle/buildBundle';