From 4906c5d10b1e05f810b98a0f3feb0817018e879e Mon Sep 17 00:00:00 2001 From: Rob Hogan Date: Tue, 6 May 2025 04:34:36 -0700 Subject: [PATCH] community-cli-plugin: Refactor CLI build command to use Metro.runBuild Summary: Metro 0.82.3's `runBuild` API now supports retrieving assets and passing through `unstable_transformProfile`, so we can use it directly in the implementation of `community-cli-plugin`'s `bundle` command with no loss of function or API change. This simplifies the implementation by re-using Metro's, and removes use of Metro internal APIs. Differential Revision: D74151840 --- .../src/commands/bundle/buildBundle.js | 80 ++++++++----------- 1 file changed, 33 insertions(+), 47 deletions(-) diff --git a/packages/community-cli-plugin/src/commands/bundle/buildBundle.js b/packages/community-cli-plugin/src/commands/bundle/buildBundle.js index 33180d7961e488..fa13ac6b651e58 100644 --- a/packages/community-cli-plugin/src/commands/bundle/buildBundle.js +++ b/packages/community-cli-plugin/src/commands/bundle/buildBundle.js @@ -10,17 +10,15 @@ */ import type {Config} from '@react-native-community/cli-types'; +import type {RunBuildOptions} from 'metro'; import type {ConfigT} from 'metro-config'; -import type {RequestOptions} from 'metro/src/shared/types.flow'; import loadMetroConfig from '../../utils/loadMetroConfig'; import parseKeyValueParamArray from '../../utils/parseKeyValueParamArray'; import saveAssets from './saveAssets'; import chalk from 'chalk'; import {promises as fs} from 'fs'; -import Server from 'metro/src/Server'; -import metroBundle from 'metro/src/shared/output/bundle'; -import metroRamBundle from 'metro/src/shared/output/RamBundle'; +import {runBuild} from 'metro'; import path from 'path'; export type BundleCommandArgs = { @@ -41,7 +39,7 @@ export type BundleCommandArgs = { sourcemapSourcesRoot?: string, sourcemapUseAbsolutePath: boolean, verbose: boolean, - unstableTransformProfile: string, + unstableTransformProfile: 'hermes-stable' | 'hermes-canary' | 'default', indexedRamBundle?: boolean, resolverOption?: Array, }; @@ -50,7 +48,7 @@ async function buildBundle( _argv: Array, ctx: Config, args: BundleCommandArgs, - bundleImpl: typeof metroBundle | typeof metroRamBundle = metroBundle, + bundleImpl?: RunBuildOptions['output'], ): Promise { const config = await loadMetroConfig(ctx, { maxWorkers: args.maxWorkers, @@ -64,7 +62,7 @@ async function buildBundle( async function buildBundleWithConfig( args: BundleCommandArgs, config: ConfigT, - bundleImpl: typeof metroBundle | typeof metroRamBundle = metroBundle, + bundleImpl?: RunBuildOptions['output'], ): Promise { const customResolverOptions = parseKeyValueParamArray( args.resolverOption ?? [], @@ -97,52 +95,40 @@ async function buildBundleWithConfig( sourceMapUrl = path.basename(sourceMapUrl); } - // $FlowIgnore[prop-missing] - const requestOpts: RequestOptions & {...} = { - entryFile: args.entryFile, - sourceMapUrl, + const runBuildOptions: RunBuildOptions = { + assets: true, + customResolverOptions, dev: args.dev, + entry: args.entryFile, minify: args.minify !== undefined ? args.minify : !args.dev, + output: bundleImpl, platform: args.platform, - // $FlowFixMe[incompatible-type] Remove suppression after Metro 0.82.3 + sourceMapUrl, unstable_transformProfile: args.unstableTransformProfile, - customResolverOptions, }; - const server = new Server(config); - - try { - const bundle = await bundleImpl.build(server, requestOpts); - - // Ensure destination directory exists before saving the bundle - await fs.mkdir(path.dirname(args.bundleOutput), { - recursive: true, - mode: 0o755, - }); - - // $FlowIgnore[class-object-subtyping] - // $FlowIgnore[incompatible-call] - // $FlowIgnore[prop-missing] - // $FlowIgnore[incompatible-exact] - await bundleImpl.save(bundle, args, console.info); - - // Save the assets of the bundle - // $FlowFixMe[prop-missing] Remove suppression after Metro 0.82.3 - const outputAssets = await server.getAssets({ - ...Server.DEFAULT_BUNDLE_OPTIONS, - ...requestOpts, - bundleType: 'todo', - }); - - // When we're done saving bundle output and the assets, we're done. - return await saveAssets( - outputAssets, - args.platform, - args.assetsDest, - args.assetCatalogDest, - ); - } finally { - await server.end(); + + // Ensure destination directory exists before running the build + await fs.mkdir(path.dirname(args.bundleOutput), { + recursive: true, + mode: 0o755, + }); + + const result = await runBuild(config, runBuildOptions); + + // Save the assets of the bundle + if (result.assets == null) { + throw new Error("Assets missing from Metro's runBuild result"); } + + const outputAssets = result.assets; + + // When we're done saving bundle output and the assets, we're done. + await saveAssets( + outputAssets, + args.platform, + args.assetsDest, + args.assetCatalogDest, + ); } /**