diff --git a/packages/metro/src/Server.js b/packages/metro/src/Server.js index 0ff4591183..b29e304a0d 100644 --- a/packages/metro/src/Server.js +++ b/packages/metro/src/Server.js @@ -17,6 +17,7 @@ import type {RamBundleInfo} from './DeltaBundler/Serializers/getRamBundleInfo'; import type { MixedOutput, Module, + ReadOnlyDependencies, ReadOnlyGraph, TransformInputOptions, TransformResult, @@ -26,6 +27,7 @@ import type {GraphId} from './lib/getGraphId'; import type {Reporter} from './lib/reporting'; import type {StackFrameInput, StackFrameOutput} from './Server/symbolicate'; import type { + BuildOptions, BundleOptions, GraphOptions, ResolverInputOptions, @@ -211,30 +213,22 @@ class Server { return this._createModuleId; } - async build(options: BundleOptions): Promise<{ - code: string, - map: string, - ... - }> { + async _serializeGraph({ + splitOptions, + prepend, + graph, + }: $ReadOnly<{ + splitOptions: SplitBundleOptions, + prepend: $ReadOnlyArray>, + graph: ReadOnlyGraph<>, + }>): Promise<{code: string, map: string}> { const { entryFile, graphOptions, - onProgress, resolverOptions, serializerOptions, transformOptions, - } = splitBundleOptions(options); - - const {prepend, graph} = await this._bundler.buildGraph( - entryFile, - transformOptions, - resolverOptions, - { - onProgress, - shallow: graphOptions.shallow, - lazy: graphOptions.lazy, - }, - ); + } = splitOptions; const entryPoint = this._getEntryPointAbsolutePath(entryFile); @@ -307,6 +301,56 @@ class Server { }; } + async build( + bundleOptions: BundleOptions, + {withAssets}: BuildOptions = {}, + ): Promise<{ + code: string, + map: string, + assets?: $ReadOnlyArray, + ... + }> { + const splitOptions = splitBundleOptions(bundleOptions); + const { + entryFile, + graphOptions, + onProgress, + resolverOptions, + transformOptions, + } = splitOptions; + + const {prepend, graph} = await this._bundler.buildGraph( + entryFile, + transformOptions, + resolverOptions, + { + onProgress, + shallow: graphOptions.shallow, + lazy: graphOptions.lazy, + }, + ); + + const [{code, map}, assets] = await Promise.all([ + this._serializeGraph({ + splitOptions, + prepend, + graph, + }), + withAssets + ? this._getAssetsFromDependencies( + graph.dependencies, + bundleOptions.platform, + ) + : null, + ]); + + return { + code, + map, + ...(withAssets ? {assets: nullthrows(assets)} : null), + }; + } + async getRamBundleInfo(options: BundleOptions): Promise { const { entryFile, @@ -377,10 +421,20 @@ class Server { {onProgress, shallow: false, lazy: false}, ); + return this._getAssetsFromDependencies( + dependencies, + transformOptions.platform, + ); + } + + async _getAssetsFromDependencies( + dependencies: ReadOnlyDependencies<>, + platform: ?string, + ): Promise<$ReadOnlyArray> { return await getAssets(dependencies, { processModuleFilter: this._config.serializer.processModuleFilter, assetPlugins: this._config.transformer.assetPlugins, - platform: transformOptions.platform, + platform, projectRoot: this._getServerRootDir(), publicPath: this._config.transformer.publicPath, }); diff --git a/packages/metro/src/index.flow.js b/packages/metro/src/index.flow.js index 25735387d8..eed42be8eb 100644 --- a/packages/metro/src/index.flow.js +++ b/packages/metro/src/index.flow.js @@ -14,6 +14,7 @@ import type {AssetData} from './Assets'; import type {ReadOnlyGraph} from './DeltaBundler'; import type {ServerOptions} from './Server'; +import type {BuildOptions} from './shared/types.flow'; import type {OutputOptions, RequestOptions} from './shared/types.flow.js'; import type {HandleFunction} from 'connect'; import type {Server as HttpServer} from 'http'; @@ -108,9 +109,11 @@ export type RunBuildOptions = { build: ( MetroServer, RequestOptions, + void | BuildOptions, ) => Promise<{ code: string, map: string, + assets?: $ReadOnlyArray, ... }>, save: ( @@ -428,10 +431,12 @@ exports.runBuild = async ( onBegin(); } - const metroBundle = await output.build(metroServer, requestOptions); + const metroBundle = await output.build(metroServer, requestOptions, { + withAssets: assets, + }); const result: RunBuildResult = {...metroBundle}; - if (assets) { + if (assets && result.assets == null) { result.assets = await metroServer.getAssets({ ...MetroServer.DEFAULT_BUNDLE_OPTIONS, ...requestOptions, diff --git a/packages/metro/src/shared/output/bundle.flow.js b/packages/metro/src/shared/output/bundle.flow.js index 241a707c37..e13b635fc0 100644 --- a/packages/metro/src/shared/output/bundle.flow.js +++ b/packages/metro/src/shared/output/bundle.flow.js @@ -11,7 +11,8 @@ 'use strict'; -import type {OutputOptions, RequestOptions} from '../types.flow'; +import type {AssetData} from '../../Assets'; +import type {BuildOptions, OutputOptions, RequestOptions} from '../types.flow'; import type {MixedSourceMap} from 'metro-source-map'; const relativizeSourceMapInline = require('../../lib/relativizeSourceMap'); @@ -21,15 +22,20 @@ const writeFile = require('./writeFile'); function buildBundle( packagerClient: Server, requestOptions: RequestOptions, + buildOptions?: BuildOptions = {}, ): Promise<{ code: string, map: string, + assets?: $ReadOnlyArray, ... }> { - return packagerClient.build({ - ...Server.DEFAULT_BUNDLE_OPTIONS, - ...requestOptions, - }); + return packagerClient.build( + { + ...Server.DEFAULT_BUNDLE_OPTIONS, + ...requestOptions, + }, + buildOptions, + ); } function relativateSerializedMap( diff --git a/packages/metro/src/shared/types.flow.js b/packages/metro/src/shared/types.flow.js index 95355c0f0f..80f100592c 100644 --- a/packages/metro/src/shared/types.flow.js +++ b/packages/metro/src/shared/types.flow.js @@ -59,6 +59,10 @@ export type BundleOptions = { +sourcePaths: SourcePathsMode, }; +export type BuildOptions = $ReadOnly<{ + withAssets?: boolean, +}>; + export type ResolverInputOptions = $ReadOnly<{ customResolverOptions?: CustomResolverOptions, dev: boolean, @@ -80,14 +84,14 @@ export type GraphOptions = { }; // Stricter representation of BundleOptions. -export type SplitBundleOptions = { - +entryFile: string, - +resolverOptions: ResolverInputOptions, - +transformOptions: TransformInputOptions, - +serializerOptions: SerializerOptions, - +graphOptions: GraphOptions, - +onProgress: DeltaBundlerOptions<>['onProgress'], -}; +export type SplitBundleOptions = $ReadOnly<{ + entryFile: string, + resolverOptions: ResolverInputOptions, + transformOptions: TransformInputOptions, + serializerOptions: SerializerOptions, + graphOptions: GraphOptions, + onProgress: DeltaBundlerOptions<>['onProgress'], +}>; export type ModuleGroups = { groups: Map>, diff --git a/packages/metro/types/Server.d.ts b/packages/metro/types/Server.d.ts index d7be6f45d9..c442f7abb1 100644 --- a/packages/metro/types/Server.d.ts +++ b/packages/metro/types/Server.d.ts @@ -13,6 +13,7 @@ import type {RamBundleInfo} from './DeltaBundler/Serializers/getRamBundleInfo'; import type {GraphId} from './lib/getGraphId'; import type MultipartResponse from './Server/MultipartResponse'; import type { + BuildOptions, BundleOptions, GraphOptions, SplitBundleOptions, @@ -94,9 +95,13 @@ export default class Server { end(): void; getBundler(): IncrementalBundler; getCreateModuleId(): (path: string) => number; - build(options: BundleOptions): Promise<{ + build( + bundleOptions: BundleOptions, + buildOptions?: BuildOptions, + ): Promise<{ code: string; map: string; + assets?: ReadonlyArray; }>; getRamBundleInfo(options: BundleOptions): Promise; getAssets(options: BundleOptions): Promise>; diff --git a/packages/metro/types/index.d.ts b/packages/metro/types/index.d.ts index 135544aef7..7446d355fb 100644 --- a/packages/metro/types/index.d.ts +++ b/packages/metro/types/index.d.ts @@ -14,9 +14,10 @@ export * from './ModuleGraph/worker/collectDependencies'; export * from './Server'; export * from './lib/reporting'; +import type {AssetData} from './Asset'; import type {ReadOnlyGraph} from './DeltaBundler/types'; import type {ServerOptions, default as MetroServer} from './Server'; -import type {OutputOptions, RequestOptions} from './shared/types'; +import type {BuildOptions, OutputOptions, RequestOptions} from './shared/types'; import type {HandleFunction} from 'connect'; import type {EventEmitter} from 'events'; import type {IncomingMessage, Server as HttpServer} from 'http'; @@ -93,10 +94,12 @@ export interface RunBuildOptions { output?: { build: ( server: MetroServer, - options: RequestOptions, + requestOptions: RequestOptions, + buildOptions?: BuildOptions, ) => Promise<{ code: string; map: string; + assets?: ReadonlyArray; }>; save: ( entry: { diff --git a/packages/metro/types/shared/output/bundle.d.ts b/packages/metro/types/shared/output/bundle.d.ts index 6ccca99d19..06c5fe6945 100644 --- a/packages/metro/types/shared/output/bundle.d.ts +++ b/packages/metro/types/shared/output/bundle.d.ts @@ -8,15 +8,19 @@ * @oncall react_native */ +import type {AssetData} from '../../Asset'; + import Server from '../../Server'; -import {OutputOptions, RequestOptions} from '../../shared/types'; +import {BuildOptions, OutputOptions, RequestOptions} from '../../shared/types'; export function build( packagerClient: Server, requestOptions: RequestOptions, + buildOptions?: BuildOptions, ): Promise<{ code: string; map: string; + assets?: ReadonlyArray; }>; export function save( diff --git a/packages/metro/types/shared/types.d.ts b/packages/metro/types/shared/types.d.ts index edc8798067..bd6bd81d97 100644 --- a/packages/metro/types/shared/types.d.ts +++ b/packages/metro/types/shared/types.d.ts @@ -47,6 +47,10 @@ export interface BundleOptions { readonly unstable_transformProfile: TransformProfile; } +export interface BuildOptions { + readonly withAssets?: boolean; +} + export interface ResolverInputOptions { readonly customResolverOptions?: CustomResolverOptions; }