diff --git a/packages/metro/src/DeltaBundler/DeltaCalculator.js b/packages/metro/src/DeltaBundler/DeltaCalculator.js index b1f18b2f..4e280fbf 100644 --- a/packages/metro/src/DeltaBundler/DeltaCalculator.js +++ b/packages/metro/src/DeltaBundler/DeltaCalculator.js @@ -42,6 +42,7 @@ export type Options = { +minify: boolean, +onProgress: ?(doneCont: number, totalCount: number) => mixed, +platform: ?string, + +type: 'module' | 'script', }; /** @@ -199,6 +200,17 @@ class DeltaCalculator extends EventEmitter { projectRoot, }; + // When we're processing scripts, we don't need to calculate any + // inlineRequires information, since scripts by definition don't have + // requires(). + if (this._options.type === 'script') { + // $FlowIssue #23854098 - Object.assign() loses the strictness of an object in flow + return { + ...transformOptionsForBlacklist, + inlineRequires: false, + }; + } + const { inlineRequires, } = await this._bundler.getTransformOptionsForEntryFiles( @@ -211,14 +223,14 @@ class DeltaCalculator extends EventEmitter { entryPoints: [path], }, this._dependencyGraph, - transformOptionsForBlacklist, + {...transformOptionsForBlacklist, type: this._options.type}, ); return Array.from(added.keys()); }, ); - // $FlowFixMe flow does not recognize well Object.assign() return types. + // $FlowIssue #23854098 - Object.assign() loses the strictness of an object in flow return { ...transformOptionsForBlacklist, inlineRequires: inlineRequires || false, @@ -267,7 +279,10 @@ class DeltaCalculator extends EventEmitter { modifiedFiles: Set, deletedFiles: Set, ): Promise { - const transformerOptions = await this.getTransformerOptions(); + const transformerOptions = { + ...(await this.getTransformerOptions()), + type: this._options.type, + }; if (!this._graph.dependencies.size) { const {added} = await initialTraverseDependencies( diff --git a/packages/metro/src/DeltaBundler/DeltaTransformer.js b/packages/metro/src/DeltaBundler/DeltaTransformer.js index 197a7bb1..cb27fbb2 100644 --- a/packages/metro/src/DeltaBundler/DeltaTransformer.js +++ b/packages/metro/src/DeltaBundler/DeltaTransformer.js @@ -126,6 +126,7 @@ class DeltaTransformer extends EventEmitter { const deltaCalculator = new DeltaCalculator(bundler, dependencyGraph, { ...bundleOptions, entryPoints: [bundleOptions.entryFile], + type: 'module', }); return new DeltaTransformer( diff --git a/packages/metro/src/DeltaBundler/traverseDependencies.js b/packages/metro/src/DeltaBundler/traverseDependencies.js index 08e50093..cb3ecc0b 100644 --- a/packages/metro/src/DeltaBundler/traverseDependencies.js +++ b/packages/metro/src/DeltaBundler/traverseDependencies.js @@ -52,6 +52,11 @@ type Delta = { deleted: Set, }; +export type TransformOptions = {| + ...JSTransformerOptions, + type: 'module' | 'script', +|}; + /** * Dependency Traversal logic for the Delta Bundler. This method calculates * the modules that should be included in the bundle by traversing the @@ -69,7 +74,7 @@ type Delta = { async function traverseDependencies( paths: $ReadOnlyArray, dependencyGraph: DependencyGraph, - transformOptions: JSTransformerOptions, + transformOptions: TransformOptions, graph: Graph, onProgress?: (numProcessed: number, total: number) => mixed = () => {}, ): Promise { @@ -136,11 +141,17 @@ async function traverseDependencies( async function initialTraverseDependencies( graph: Graph, dependencyGraph: DependencyGraph, - transformOptions: JSTransformerOptions, + transformOptions: TransformOptions, onProgress?: (numProcessed: number, total: number) => mixed = () => {}, ): Promise { graph.entryPoints.forEach(entryPoint => - createEdge(dependencyGraph.getModuleForPath(entryPoint), graph), + createEdge( + dependencyGraph.getModuleForPath( + entryPoint, + transformOptions.type === 'script', + ), + graph, + ), ); await traverseDependencies( @@ -162,7 +173,7 @@ async function initialTraverseDependencies( async function traverseDependenciesForSingleFile( edge: DependencyEdge, dependencyGraph: DependencyGraph, - transformOptions: JSTransformerOptions, + transformOptions: TransformOptions, graph: Graph, delta: Delta, onProgress?: (numProcessed: number, total: number) => mixed = () => {}, @@ -194,7 +205,7 @@ async function traverseDependenciesForSingleFile( async function processEdge( edge: DependencyEdge, dependencyGraph: DependencyGraph, - transformOptions: JSTransformerOptions, + transformOptions: TransformOptions, graph: Graph, delta: Delta, onDependencyAdd: () => mixed, @@ -202,11 +213,12 @@ async function processEdge( ): Promise { const previousDependencies = edge.dependencies; - const result = await dependencyGraph - .getModuleForPath(edge.path) - .read( - removeInlineRequiresBlacklistFromOptions(edge.path, transformOptions), - ); + const {type, ...workerTransformOptions} = transformOptions; + + const module = dependencyGraph.getModuleForPath(edge.path, type === 'script'); + const result = await module.read( + removeInlineRequiresBlacklistFromOptions(edge.path, workerTransformOptions), + ); // Get the absolute path of all sub-dependencies (some of them could have been // moved but maintain the same relative path). @@ -262,7 +274,7 @@ async function addDependency( parentEdge: DependencyEdge, path: string, dependencyGraph: DependencyGraph, - transformOptions: JSTransformerOptions, + transformOptions: TransformOptions, graph: Graph, delta: Delta, onDependencyAdd: () => mixed, @@ -277,7 +289,10 @@ async function addDependency( return; } - const edge = createEdge(dependencyGraph.getModuleForPath(path), graph); + const edge = createEdge( + dependencyGraph.getModuleForPath(path, transformOptions.type === 'script'), + graph, + ); edge.inverseDependencies.add(parentEdge.path); delta.added.set(edge.path, edge); @@ -365,11 +380,14 @@ function destroyEdge(edge: DependencyEdge, graph: Graph) { function resolveDependencies( parentPath, - dependencies: Array, + dependencies: $ReadOnlyArray, dependencyGraph: DependencyGraph, - transformOptions: JSTransformerOptions, + transformOptions: TransformOptions, ): Map { - const parentModule = dependencyGraph.getModuleForPath(parentPath); + const parentModule = dependencyGraph.getModuleForPath( + parentPath, + transformOptions.type === 'string', + ); return new Map( dependencies.map(relativePath => [ diff --git a/packages/metro/src/Server/__tests__/Server-test.js b/packages/metro/src/Server/__tests__/Server-test.js index 0d677a85..d0f4cd30 100644 --- a/packages/metro/src/Server/__tests__/Server-test.js +++ b/packages/metro/src/Server/__tests__/Server-test.js @@ -466,6 +466,7 @@ describe('processRequest', () => { minify: false, onProgress: null, platform: undefined, + type: 'module', }), ); }); diff --git a/packages/metro/src/Server/index.js b/packages/metro/src/Server/index.js index 821e34ba..64b24138 100644 --- a/packages/metro/src/Server/index.js +++ b/packages/metro/src/Server/index.js @@ -245,7 +245,7 @@ class Server { this._opts.projectRoots, ); - let graph = await this._deltaBundler.buildGraph({ + const crawlingOptions = { assetPlugins: options.assetPlugins, customTransformOptions: options.customTransformOptions, dev: options.dev, @@ -254,11 +254,14 @@ class Server { minify: options.minify, onProgress: options.onProgress, platform: options.platform, - }); + type: 'module', + }; + + let graph = await this._deltaBundler.buildGraph(crawlingOptions); let prependScripts = await getPrependedScripts( this._opts, - options, - this._bundler, + crawlingOptions, + this._deltaBundler, ); if (options.minify) { @@ -973,6 +976,7 @@ class Server { runBeforeMainModule: [], runModule: true, sourceMapUrl: null, + type: 'script', unbundle: false, }; } diff --git a/packages/metro/src/__fixtures__/getTransformOptions.js b/packages/metro/src/__fixtures__/getTransformOptions.js index 61ea5eec..dcb6a6db 100644 --- a/packages/metro/src/__fixtures__/getTransformOptions.js +++ b/packages/metro/src/__fixtures__/getTransformOptions.js @@ -43,6 +43,7 @@ async function getTransformOptions(): Promise { hot: true, minify: false, platform: 'ios', + type: 'module', }; const deltaCalculator = new DeltaCalculator( diff --git a/packages/metro/src/lib/getPrependedScripts.js b/packages/metro/src/lib/getPrependedScripts.js index 36085197..224471d6 100644 --- a/packages/metro/src/lib/getPrependedScripts.js +++ b/packages/metro/src/lib/getPrependedScripts.js @@ -13,27 +13,27 @@ const defaults = require('../defaults'); const getPreludeCode = require('./getPreludeCode'); -import type Bundler from '../Bundler'; import type {DependencyEdge} from '../DeltaBundler/traverseDependencies'; -import type Module from '../node-haste/Module'; +import type DeltaBundler from '../DeltaBundler'; +import type {CustomTransformOptions} from '../JSTransformer/worker'; type Options = { - enableBabelRCLookup: boolean, getPolyfills: ({platform: ?string}) => $ReadOnlyArray, polyfillModuleNames: Array, - projectRoots: $ReadOnlyArray, }; type BundleOptions = { + customTransformOptions: CustomTransformOptions, +dev: boolean, +hot: boolean, + +minify: boolean, +platform: ?string, }; async function getPrependedScripts( options: Options, bundleOptions: BundleOptions, - bundler: Bundler, + deltaBundler: DeltaBundler, ): Promise> { // Get all the polyfills from the relevant option params (the // `getPolyfills()` method and the `polyfillModuleNames` variable). @@ -43,32 +43,22 @@ async function getPrependedScripts( }) .concat(options.polyfillModuleNames); - const dependencyGraph = await bundler.getDependencyGraph(); - - // Build the module system dependencies (scripts that need to - // be included at the very beginning of the bundle) + any polifyll. - const modules = [defaults.moduleSystem] - .concat(polyfillModuleNames) - .map(polyfillModuleName => - dependencyGraph.createPolyfill({ - file: polyfillModuleName, - }), - ); - - const transformOptions = { + const graph = await deltaBundler.buildGraph({ + assetPlugins: [], + customTransformOptions: bundleOptions.customTransformOptions, dev: bundleOptions.dev, - enableBabelRCLookup: options.enableBabelRCLookup, + entryPoints: [defaults.moduleSystem, ...polyfillModuleNames], hot: bundleOptions.hot, - projectRoot: options.projectRoots[0], - }; + minify: bundleOptions.minify, + onProgress: null, + platform: bundleOptions.platform, + type: 'script', + }); - const out = await Promise.all( - modules.map(module => _createEdgeFromScript(module, transformOptions)), - ); - - out.unshift(_getPrelude({dev: bundleOptions.dev})); - - return out; + return [ + _getPrelude({dev: bundleOptions.dev}), + ...graph.dependencies.values(), + ]; } function _getPrelude({dev}: {dev: boolean}): DependencyEdge { @@ -88,38 +78,4 @@ function _getPrelude({dev}: {dev: boolean}): DependencyEdge { }; } -async function _createEdgeFromScript( - module: Module, - options: { - dev: boolean, - enableBabelRCLookup: boolean, - hot: boolean, - projectRoot: string, - }, -): Promise { - const result = await module.read({ - assetDataPlugins: [], - customTransformOptions: {}, - dev: options.dev, - enableBabelRCLookup: options.enableBabelRCLookup, - hot: options.hot, - inlineRequires: false, - minify: false, - platform: undefined, - projectRoot: options.projectRoot, - }); - - return { - dependencies: new Map(), - inverseDependencies: new Set(), - path: module.path, - output: { - code: result.code, - map: result.map, - source: result.source, - type: 'script', - }, - }; -} - module.exports = getPrependedScripts; diff --git a/packages/metro/src/node-haste/DependencyGraph.js b/packages/metro/src/node-haste/DependencyGraph.js index aa940ffb..c5c669e9 100644 --- a/packages/metro/src/node-haste/DependencyGraph.js +++ b/packages/metro/src/node-haste/DependencyGraph.js @@ -238,7 +238,11 @@ class DependencyGraph extends EventEmitter { this._haste.end(); } - getModuleForPath(entryFile: string) { + getModuleForPath(entryFile: string, isPolyfill: boolean): Module { + if (isPolyfill) { + return this._moduleCache.getPolyfillModule(entryFile); + } + if (this._helpers.isAssetFile(entryFile)) { return this._moduleCache.getAssetModule(entryFile); } diff --git a/packages/metro/src/node-haste/ModuleCache.js b/packages/metro/src/node-haste/ModuleCache.js index a3f07eb6..d3b4b30b 100644 --- a/packages/metro/src/node-haste/ModuleCache.js +++ b/packages/metro/src/node-haste/ModuleCache.js @@ -87,7 +87,7 @@ class ModuleCache { this._roots = roots; } - getModule(filePath: string): Module { + getModule(filePath: string) { if (!this._moduleCache[filePath]) { this._moduleCache[filePath] = new Module({ depGraphHelpers: this._depGraphHelpers, @@ -129,6 +129,14 @@ class ModuleCache { return this._moduleCache[filePath]; } + getPolyfillModule(filePath: string) { + if (!this._moduleCache[filePath]) { + this._moduleCache[filePath] = this.createPolyfill({file: filePath}); + } + + return this._moduleCache[filePath]; + } + getPackage(filePath: string): Package { if (!this._packageCache[filePath]) { this._packageCache[filePath] = new Package({ diff --git a/packages/metro/src/transformer.js b/packages/metro/src/transformer.js index c4c2c99a..b148fbda 100644 --- a/packages/metro/src/transformer.js +++ b/packages/metro/src/transformer.js @@ -119,14 +119,6 @@ type Params = { }; function transform({filename, options, src, plugins}: Params) { - options = options || { - assetDataPlugins: [], - platform: '', - projectRoot: '', - inlineRequires: false, - minify: false, - }; - const OLD_BABEL_ENV = process.env.BABEL_ENV; process.env.BABEL_ENV = options.dev ? 'development' : 'production';