From 0520fb254bf568098fdfff868e51bab5f5ec0a9d Mon Sep 17 00:00:00 2001 From: Rafael Oleza Date: Tue, 20 Mar 2018 06:53:15 -0700 Subject: [PATCH] Use the new Graph object for generating assets Reviewed By: mjesun Differential Revision: D7275601 fbshipit-source-id: b7c03ec35ea1994e2441da2889a44466e9e2aa0f --- .../DeltaBundler/Serializers/Serializers.js | 30 ------ .../Serializers/__tests__/Serializers-test.js | 38 ------- .../__snapshots__/Serializers-test.js.snap | 44 -------- .../Serializers/__tests__/getAssets-test.js | 41 +++++++ .../src/DeltaBundler/Serializers/getAssets.js | 47 ++++++++ packages/metro/src/Server/index.js | 101 +++++++++++------- 6 files changed, 149 insertions(+), 152 deletions(-) create mode 100644 packages/metro/src/DeltaBundler/Serializers/__tests__/getAssets-test.js create mode 100644 packages/metro/src/DeltaBundler/Serializers/getAssets.js diff --git a/packages/metro/src/DeltaBundler/Serializers/Serializers.js b/packages/metro/src/DeltaBundler/Serializers/Serializers.js index 43ce1c4a..a5739010 100644 --- a/packages/metro/src/DeltaBundler/Serializers/Serializers.js +++ b/packages/metro/src/DeltaBundler/Serializers/Serializers.js @@ -14,13 +14,10 @@ const DeltaPatcher = require('../DeltaPatcher'); const RamBundle = require('./RamBundle'); const stableHash = require('metro-cache/src/stableHash'); -const toLocalPath = require('../../node-haste/lib/toLocalPath'); -const {getAssetData} = require('../../Assets'); const {createRamBundleGroups} = require('../../Bundler/util'); const {fromRawMappings} = require('metro-source-map'); -import type {AssetData} from '../../Assets'; import type {GetTransformOptions} from '../../Bundler'; import type {BundleOptions, ModuleTransportLike} from '../../shared/types.flow'; import type DeltaBundler from '../'; @@ -241,32 +238,6 @@ async function getRamBundleInfo( }; } -async function getAssets( - deltaBundler: DeltaBundler, - options: BundleOptions, - projectRoots: $ReadOnlyArray, -): Promise<$ReadOnlyArray> { - const {modules} = await _getAllModules(deltaBundler, options); - - const assets = await Promise.all( - modules.map(async module => { - if (module.type === 'asset') { - const localPath = toLocalPath(projectRoots, module.path); - - return getAssetData( - module.path, - localPath, - options.assetPlugins, - options.platform, - ); - } - return null; - }), - ); - - return assets.filter(Boolean); -} - async function _build( deltaBundler: DeltaBundler, clientId: string, @@ -294,6 +265,5 @@ module.exports = { fullSourceMap, fullSourceMapObject, getAllModules, - getAssets, getRamBundleInfo, }; diff --git a/packages/metro/src/DeltaBundler/Serializers/__tests__/Serializers-test.js b/packages/metro/src/DeltaBundler/Serializers/__tests__/Serializers-test.js index a56f4c81..79707b8c 100644 --- a/packages/metro/src/DeltaBundler/Serializers/__tests__/Serializers-test.js +++ b/packages/metro/src/DeltaBundler/Serializers/__tests__/Serializers-test.js @@ -13,7 +13,6 @@ jest.mock('../../../node-haste/lib/toLocalPath'); jest.mock('../../../Assets'); -const {getAssetData} = require('../../../Assets'); const toLocalPath = require('../../../node-haste/lib/toLocalPath'); const CURRENT_TIME = 1482363367000; @@ -61,14 +60,6 @@ describe('Serializers', () => { }, }; - getAssetData.mockImplementation( - (path, localPath, assetDataPlugins, platform) => ({ - path, - platform, - assetData: true, - }), - ); - toLocalPath.mockImplementation((roots, path) => path.replace(roots[0], '')); setCurrentTime(CURRENT_TIME); @@ -235,35 +226,6 @@ describe('Serializers', () => { ).toMatchSnapshot(); }); - it('should return the bundle assets', async () => { - expect(await Serializers.getAllModules(deltaBundler, {})).toMatchSnapshot(); - - getDelta.mockReturnValueOnce( - Promise.resolve({ - delta: new Map([ - [3, {code: 'modified module;'}], - [7, {code: 'code', type: 'asset', path: '/foo/path.png'}], - [8, {code: 'code', type: 'module', path: '/foo/path2.png'}], - [9, {code: 'code', type: 'asset', path: '/foo/path3.png'}], - ]), - pre: new Map([[5, {code: 'more pre;'}]]), - post: new Map([[6, {code: 'bananas;'}]]), - inverseDependencies: [], - reset: true, - }), - ); - - expect( - await Serializers.getAssets( - deltaBundler, - { - platform: 'ios', - }, - ['/foo'], - ), - ).toMatchSnapshot(); - }); - it('should post-process the modules', async () => { postProcessModules.mockImplementation(modules => { return modules.sort( diff --git a/packages/metro/src/DeltaBundler/Serializers/__tests__/__snapshots__/Serializers-test.js.snap b/packages/metro/src/DeltaBundler/Serializers/__tests__/__snapshots__/Serializers-test.js.snap index 00d4a8f7..c860c918 100644 --- a/packages/metro/src/DeltaBundler/Serializers/__tests__/__snapshots__/Serializers-test.js.snap +++ b/packages/metro/src/DeltaBundler/Serializers/__tests__/__snapshots__/Serializers-test.js.snap @@ -345,50 +345,6 @@ Object { } `; -exports[`Serializers should return the bundle assets 1`] = ` -Array [ - Object { - "code": "pre;", - "id": 1, - "path": "/pre.js", - "type": "script", - }, - Object { - "code": "module3;", - "id": 3, - "path": "/3.js", - "type": "module", - }, - Object { - "code": "another;", - "id": 4, - "path": "/4.js", - "type": "module", - }, - Object { - "code": "post;", - "id": 2, - "path": "/p", - "type": "require", - }, -] -`; - -exports[`Serializers should return the bundle assets 2`] = ` -Array [ - Object { - "assetData": true, - "path": "/foo/path.png", - "platform": "ios", - }, - Object { - "assetData": true, - "path": "/foo/path3.png", - "platform": "ios", - }, -] -`; - exports[`Serializers should return the stringified delta bundle 1`] = ` Object { "bundle": "{\\"id\\":\\"1234\\",\\"pre\\":[[1,\\"pre;\\"]],\\"post\\":[[2,\\"post;\\"]],\\"delta\\":[[3,\\"module3;\\"],[4,\\"another;\\"]],\\"reset\\":true}", diff --git a/packages/metro/src/DeltaBundler/Serializers/__tests__/getAssets-test.js b/packages/metro/src/DeltaBundler/Serializers/__tests__/getAssets-test.js new file mode 100644 index 00000000..e331ae30 --- /dev/null +++ b/packages/metro/src/DeltaBundler/Serializers/__tests__/getAssets-test.js @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @emails oncall+javascript_foundation + * @format + */ + +'use strict'; + +jest.mock('../../../Assets'); + +const getAssets = require('../getAssets'); + +const {getAssetData} = require('../../../Assets'); + +beforeEach(() => { + getAssetData.mockImplementation(async (path, localPath) => ({ + path, + localPath, + })); +}); + +it('should return the bundle assets', async () => { + const graph = { + dependencies: new Map([ + ['/tmp/1.js', {path: '/tmp/1.js', output: {type: 'module'}}], + ['/tmp/2.js', {path: '/tmp/2.js', output: {type: 'module'}}], + ['/tmp/3.png', {path: '/tmp/3.png', output: {type: 'asset'}}], + ['/tmp/4.js', {path: '/tmp/2.js', output: {type: 'module'}}], + ['/tmp/5.mov', {path: '/tmp/5.mov', output: {type: 'asset'}}], + ]), + }; + + expect(await getAssets(graph, {projectRoots: ['/tmp']})).toEqual([ + {path: '/tmp/3.png', localPath: '3.png'}, + {path: '/tmp/5.mov', localPath: '5.mov'}, + ]); +}); diff --git a/packages/metro/src/DeltaBundler/Serializers/getAssets.js b/packages/metro/src/DeltaBundler/Serializers/getAssets.js new file mode 100644 index 00000000..89aa2dad --- /dev/null +++ b/packages/metro/src/DeltaBundler/Serializers/getAssets.js @@ -0,0 +1,47 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + * @format + */ + +'use strict'; + +const toLocalPath = require('../../node-haste/lib/toLocalPath'); + +const {getAssetData} = require('../../Assets'); + +import type {AssetData} from '../../Assets'; +import type {Graph} from '../DeltaCalculator'; + +type Options = {| + assetPlugins: $ReadOnlyArray, + platform: ?string, + projectRoots: $ReadOnlyArray, +|}; + +async function getAssets( + graph: Graph, + options: Options, +): Promise<$ReadOnlyArray> { + const assets = await Promise.all( + Array.from(graph.dependencies.values()).map(async module => { + if (module.output.type === 'asset') { + return getAssetData( + module.path, + toLocalPath(options.projectRoots, module.path), + options.assetPlugins, + options.platform, + ); + } + return null; + }), + ); + + return assets.filter(Boolean); +} + +module.exports = getAssets; diff --git a/packages/metro/src/Server/index.js b/packages/metro/src/Server/index.js index ba1818e9..b4ab61c3 100644 --- a/packages/metro/src/Server/index.js +++ b/packages/metro/src/Server/index.js @@ -16,6 +16,7 @@ const MultipartResponse = require('./MultipartResponse'); const Serializers = require('../DeltaBundler/Serializers/Serializers'); const defaultCreateModuleIdFactory = require('../lib/createModuleIdFactory'); +const getAssets = require('../DeltaBundler/Serializers/getAssets'); const plainJSBundle = require('../DeltaBundler/Serializers/plainJSBundle'); const sourceMapString = require('../DeltaBundler/Serializers/sourceMapString'); const debug = require('debug')('Metro:Server'); @@ -52,6 +53,7 @@ import type { PostProcessBundleSourcemap, } from '../Bundler'; import type {CacheStore} from 'metro-cache'; +import type {Graph} from '../DeltaBundler'; import type {MetroSourceMap} from 'metro-source-map'; import type {TransformCache} from '../lib/TransformCaching'; import type {Symbolicate} from './symbolicate/symbolicate'; @@ -64,6 +66,11 @@ const { type ResolveSync = (path: string, opts: ?{baseDir?: string}) => string; +type GraphInfo = {| + graph: Graph, + prepend: $ReadOnlyArray, +|}; + function debounceAndBatch(fn, delay) { let timeout; return () => { @@ -243,49 +250,22 @@ class Server { } async build(options: BundleOptions): Promise<{code: string, map: string}> { + const {prepend, graph} = await this._buildGraph(options); + const entryPoint = getAbsolutePath( options.entryFile, this._opts.projectRoots, ); - const crawlingOptions = { - assetPlugins: options.assetPlugins, - customTransformOptions: options.customTransformOptions, - dev: options.dev, - entryPoints: [entryPoint], - hot: options.hot, - minify: options.minify, - onProgress: options.onProgress, - platform: options.platform, - type: 'module', - }; - - let graph = await this._deltaBundler.buildGraph(crawlingOptions); - let prependScripts = await getPrependedScripts( - this._opts, - crawlingOptions, - this._deltaBundler, - ); - - if (options.minify) { - prependScripts = await Promise.all( - prependScripts.map(script => this._minifyModule(script)), - ); - - graph = await mapGraph(graph, module => this._minifyModule(module)); - } - return { - code: plainJSBundle(entryPoint, prependScripts, graph, { + code: plainJSBundle(entryPoint, prepend, graph, { createModuleId: this._opts.createModuleId, dev: options.dev, - runBeforeMainModule: this._opts.getModulesRunBeforeMainModule( - options.entryFile, - ), + runBeforeMainModule: options.runBeforeMainModule, runModule: options.runModule, sourceMapUrl: options.sourceMapUrl, }), - map: sourceMapString(prependScripts, graph, { + map: sourceMapString(prepend, graph, { excludeSource: options.excludeSource, }), }; @@ -303,14 +283,16 @@ class Server { } async getAssets(options: BundleOptions): Promise<$ReadOnlyArray> { - return await Serializers.getAssets( - this._deltaBundler, - { - ...options, - entryFile: getAbsolutePath(options.entryFile, this._opts.projectRoots), - }, - this._opts.projectRoots, - ); + const {graph} = await this._buildGraph({ + ...options, + minify: false, // minification does not affect the assets. + }); + + return await getAssets(graph, { + assetPlugins: options.assetPlugins, + platform: options.platform, + projectRoots: this._opts.projectRoots, + }); } async getOrderedDependencyPaths(options: { @@ -336,6 +318,45 @@ class Server { return await getOrderedDependencyPaths(this._deltaBundler, bundleOptions); } + async _buildGraph(options: BundleOptions): Promise { + const entryPoint = getAbsolutePath( + options.entryFile, + this._opts.projectRoots, + ); + + const crawlingOptions = { + assetPlugins: options.assetPlugins, + customTransformOptions: options.customTransformOptions, + dev: options.dev, + entryPoints: [entryPoint], + hot: options.hot, + minify: options.minify, + onProgress: options.onProgress, + platform: options.platform, + type: 'module', + }; + + let graph = await this._deltaBundler.buildGraph(crawlingOptions); + let prepend = await getPrependedScripts( + this._opts, + crawlingOptions, + this._deltaBundler, + ); + + if (options.minify) { + prepend = await Promise.all( + prepend.map(script => this._minifyModule(script)), + ); + + graph = await mapGraph(graph, module => this._minifyModule(module)); + } + + return { + prepend, + graph, + }; + } + async _minifyModule(module: DependencyEdge): Promise { const {code, map} = await this._bundler.minifyModule( module.path,