Use the new Graph object for generating assets

Reviewed By: mjesun

Differential Revision: D7275601

fbshipit-source-id: b7c03ec35ea1994e2441da2889a44466e9e2aa0f
This commit is contained in:
Rafael Oleza 2018-03-20 06:53:15 -07:00 committed by Facebook Github Bot
parent ce2ee5a19c
commit 0520fb254b
6 changed files with 149 additions and 152 deletions

View File

@ -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<string>,
): Promise<$ReadOnlyArray<AssetData>> {
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,
};

View File

@ -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(

View File

@ -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}",

View File

@ -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'},
]);
});

View File

@ -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<string>,
platform: ?string,
projectRoots: $ReadOnlyArray<string>,
|};
async function getAssets(
graph: Graph,
options: Options,
): Promise<$ReadOnlyArray<AssetData>> {
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;

View File

@ -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<DependencyEdge>,
|};
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<AssetData>> {
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<GraphInfo> {
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<DependencyEdge> {
const {code, map} = await this._bundler.minifyModule(
module.path,