diff --git a/packages/metro-bundler/src/ModuleGraph/ModuleGraph.js b/packages/metro-bundler/src/ModuleGraph/ModuleGraph.js index 4518ca50..a56ae701 100644 --- a/packages/metro-bundler/src/ModuleGraph/ModuleGraph.js +++ b/packages/metro-bundler/src/ModuleGraph/ModuleGraph.js @@ -7,29 +7,25 @@ * of patent rights can be found in the PATENTS file in the same directory. * * @flow + * @format */ 'use strict'; const defaults = require('../defaults'); -const nullthrows = require('fbjs/lib/nullthrows'); -const parallel = require('async/parallel'); -const seq = require('async/seq'); +const denodeify: Denodeify = require('denodeify'); const virtualModule = require('./module').virtual; import type { BuildResult, Callback, GraphFn, - GraphResult, - Module, PostProcessModules, } from './types.flow'; -type BuildFn = ( +export type BuildFn = ( entryPoints: Iterable, options: BuildOptions, - callback: Callback, -) => void; +) => Promise; type BuildOptions = {| getPolyfills: ({platform: ?string}) => $ReadOnlyArray, @@ -37,78 +33,50 @@ type BuildOptions = {| platform: string, |}; +type Denodeify = ( + (A, B, C, Callback) => void, +) => (A, B, C) => Promise; + exports.createBuildSetup = ( - graph: GraphFn, + graphFn: GraphFn, postProcessModules: PostProcessModules, translateDefaultsPath: string => string = x => x, -): BuildFn => - (entryPoints, options, callback) => { - const { - getPolyfills = (({platform}) => []), - optimize = false, - platform = defaults.platforms[0], - } = options; - const graphOptions = {optimize}; +): BuildFn => async (entryPoints, options) => { + const { + getPolyfills = ({platform}) => [], + optimize = false, + platform = defaults.platforms[0], + } = options; + const graphOptions = {optimize}; - const graphWithOptions = - (entry, cb) => graph(entry, platform, graphOptions, cb); - const graphOnlyModules = seq(graphWithOptions, getModules); + const pgraph = denodeify(graphFn); + const graphWithOptions = entry => pgraph(entry, platform, graphOptions); + const graphOnlyModules = async m => (await graphWithOptions(m)).modules; - parallel({ - graph: cb => graphWithOptions(entryPoints, (error, result) => { - if (error) { - cb(error); - return; - } - /* $FlowFixMe: not undefined if there is no error */ - const {modules, entryModules} = result; - const prModules = postProcessModules(modules, [...entryPoints]); - cb(null, {modules: prModules, entryModules}); - }), - moduleSystem: cb => graphOnlyModules( - [translateDefaultsPath(defaults.moduleSystem)], - cb, - ), - polyfills: cb => graphOnlyModules( - getPolyfills({platform}).map(translateDefaultsPath), - cb, - ), - }, ( - error: ?Error, - result?: {graph: GraphResult, moduleSystem: Array, polyfills: Array}, - ) => { - if (error) { - callback(error); - return; - } + const [graph, moduleSystem, polyfills] = await Promise.all([ + (async () => { + const result = await graphWithOptions(entryPoints); + const {modules, entryModules} = result; + const prModules = postProcessModules(modules, [...entryPoints]); + return {modules: prModules, entryModules}; + })(), + graphOnlyModules([translateDefaultsPath(defaults.moduleSystem)]), + graphOnlyModules(getPolyfills({platform}).map(translateDefaultsPath)), + ]); - const { - graph: {modules, entryModules}, - moduleSystem, - polyfills, - } = nullthrows(result); - - const preludeScript = prelude(optimize); - const prependedScripts = [preludeScript, ...moduleSystem, ...polyfills]; - callback(null, { - entryModules, - modules: prependedScripts.concat(modules), - prependedScripts, - }); - }); + const {entryModules} = graph; + const preludeScript = prelude(optimize); + const prependedScripts = [preludeScript, ...moduleSystem, ...polyfills]; + return { + entryModules, + modules: [...prependedScripts, ...graph.modules], + prependedScripts, }; - -const getModules = (x, cb) => cb(null, x.modules); - -function* concat(...iterables: Array>): Iterable { - for (const it of iterables) { - yield* it; - } -} +}; function prelude(optimize) { return virtualModule( `var __DEV__=${String(!optimize)},` + - '__BUNDLE_START_TIME__=this.nativePerformanceNow?nativePerformanceNow():Date.now();' + '__BUNDLE_START_TIME__=this.nativePerformanceNow?nativePerformanceNow():Date.now();', ); } diff --git a/packages/metro-bundler/src/ModuleGraph/__tests__/ModuleGraph-test.js b/packages/metro-bundler/src/ModuleGraph/__tests__/ModuleGraph-test.js index 9607ae20..e7667867 100644 --- a/packages/metro-bundler/src/ModuleGraph/__tests__/ModuleGraph-test.js +++ b/packages/metro-bundler/src/ModuleGraph/__tests__/ModuleGraph-test.js @@ -5,10 +5,15 @@ * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. + * + * @emails oncall+javascript_foundation + * @format */ + 'use strict'; const ModuleGraph = require('../ModuleGraph'); + const defaults = require('../../defaults'); const FILE_TYPE = 'module'; @@ -21,66 +26,58 @@ describe('build setup', () => { const noOptions = {}; const noEntryPoints = []; - it('adds a prelude containing start time and `__DEV__` to the build', done => { - buildSetup(noEntryPoints, noOptions, (error, result) => { - expect(error).toEqual(null); + it('adds a prelude containing start time and `__DEV__` to the build', async () => { + const result = await buildSetup(noEntryPoints, noOptions); - const [prelude] = result.modules; - expect(prelude).toEqual({ - dependencies: [], - file: { - code: 'var __DEV__=true,__BUNDLE_START_TIME__=' + - 'this.nativePerformanceNow?nativePerformanceNow():Date.now();', - map: null, - path: '', - type: 'script', - }, - }); - done(); + const [prelude] = result.modules; + expect(prelude).toEqual({ + dependencies: [], + file: { + code: + 'var __DEV__=true,__BUNDLE_START_TIME__=' + + 'this.nativePerformanceNow?nativePerformanceNow():Date.now();', + map: null, + path: '', + type: 'script', + }, }); }); - it('sets `__DEV__` to false in the prelude if optimization is enabled', done => { - buildSetup(noEntryPoints, {optimize: true}, (error, result) => { - const [prelude] = result.modules; - expect(prelude.file.code) - .toEqual('var __DEV__=false,__BUNDLE_START_TIME__=' + - 'this.nativePerformanceNow?nativePerformanceNow():Date.now();'); - done(); + it('sets `__DEV__` to false in the prelude if optimization is enabled', async () => { + const result = await buildSetup(noEntryPoints, {optimize: true}); + const [prelude] = result.modules; + expect(prelude.file.code).toEqual( + 'var __DEV__=false,__BUNDLE_START_TIME__=' + + 'this.nativePerformanceNow?nativePerformanceNow():Date.now();', + ); + }); + + it('places the module system implementation directly after the prelude', async () => { + const result = await buildSetup(noEntryPoints, noOptions); + const [, moduleSystem] = result.modules; + expect(moduleSystem).toEqual({ + dependencies: [], + file: { + code: '', + path: defaults.moduleSystem, + type: FILE_TYPE, + }, }); }); - it('places the module system implementation directly after the prelude', done => { - buildSetup(noEntryPoints, noOptions, (error, result) => { - const [, moduleSystem] = result.modules; - expect(moduleSystem).toEqual({ - dependencies: [], - file: { - code: '', - path: defaults.moduleSystem, - type: FILE_TYPE, - }, - }); - done(); - }); + it('places polyfills after the module system', async () => { + const result = await buildSetup(noEntryPoints, polyfillOptions); + const list = polyfillOptions.getPolyfills(); + const polyfills = result.modules.slice(2, list.length + 2); + expect(polyfills).toEqual(list.map(moduleFromPath)); }); - it('places polyfills after the module system', done => { - buildSetup(noEntryPoints, polyfillOptions, (error, result) => { - const list = polyfillOptions.getPolyfills(); - const polyfills = result.modules.slice(2, list.length + 2); - expect(polyfills).toEqual(list.map(moduleFromPath)); - done(); - }); - }); - - it('places all entry points and dependencies at the end, post-processed', done => { + it('places all entry points and dependencies at the end, post-processed', async () => { const entryPoints = ['b', 'c', 'd']; - buildSetup(entryPoints, noOptions, (error, result) => { - expect(result.modules.slice(-4)) - .toEqual(['a', 'b', 'c', 'd'].map(moduleFromPath)); - done(); - }); + const result = await buildSetup(entryPoints, noOptions); + expect(result.modules.slice(-4)).toEqual( + ['a', 'b', 'c', 'd'].map(moduleFromPath), + ); }); });