Prepare metro to build production bundles using the Delta Bundler

Reviewed By: davidaurelio

Differential Revision: D6186012

fbshipit-source-id: a9c2757211345881e3feba331bdbe66cdc0f6b97
This commit is contained in:
Rafael Oleza 2017-10-31 10:17:35 -07:00 committed by Facebook Github Bot
parent 775867445a
commit ff7ec2e6bf
6 changed files with 460 additions and 4 deletions

View File

@ -248,6 +248,10 @@ class Bundler {
this._getTransformOptions = opts.getTransformOptions; this._getTransformOptions = opts.getTransformOptions;
} }
getAssetServer(): AssetServer {
return this._assetServer;
}
end() { end() {
this._transformer.kill(); this._transformer.kill();
/* $FlowFixMe(>=0.54.0 site=react_native_fb) This comment suppresses an /* $FlowFixMe(>=0.54.0 site=react_native_fb) This comment suppresses an

View File

@ -16,8 +16,10 @@ const DeltaPatcher = require('./DeltaPatcher');
const {fromRawMappings} = require('../Bundler/source-map'); const {fromRawMappings} = require('../Bundler/source-map');
import type {AssetData} from '../AssetServer';
import type {BundleOptions} from '../Server'; import type {BundleOptions} from '../Server';
import type {MappingsMap} from '../lib/SourceMap'; import type {MappingsMap} from '../lib/SourceMap';
import type {ModuleTransportLike} from '../shared/types.flow';
import type DeltaBundler, {Options as BuildOptions} from './'; import type DeltaBundler, {Options as BuildOptions} from './';
import type {DeltaEntry, DeltaTransformResponse} from './DeltaTransformer'; import type {DeltaEntry, DeltaTransformResponse} from './DeltaTransformer';
@ -25,6 +27,14 @@ export type Options = BundleOptions & {
deltaBundleId: ?string, deltaBundleId: ?string,
}; };
export type RamModule = ModuleTransportLike;
export type RamBundleInfo = {
startupModules: $ReadOnlyArray<ModuleTransportLike>,
lazyModules: $ReadOnlyArray<ModuleTransportLike>,
groups: Map<number, Set<number>>,
};
/** /**
* This module contains many serializers for the Delta Bundler. Each serializer * This module contains many serializers for the Delta Bundler. Each serializer
* returns a string representation for any specific type of bundle, which can * returns a string representation for any specific type of bundle, which can
@ -115,7 +125,7 @@ async function fullBundle(
async function getAllModules( async function getAllModules(
deltaBundler: DeltaBundler, deltaBundler: DeltaBundler,
options: Options, options: Options,
): Promise<Array<DeltaEntry>> { ): Promise<$ReadOnlyArray<DeltaEntry>> {
const {id, delta} = await _build(deltaBundler, { const {id, delta} = await _build(deltaBundler, {
...options, ...options,
wrapModules: true, wrapModules: true,
@ -126,6 +136,59 @@ async function getAllModules(
.getAllModules(); .getAllModules();
} }
async function getRamBundleInfo(
deltaBundler: DeltaBundler,
options: Options,
): Promise<RamBundleInfo> {
let modules = await getAllModules(deltaBundler, options);
modules = modules.map(module => {
const map = fromRawMappings([module]).toMap(module.path, {
excludeSource: options.excludeSource,
});
return {
id: module.id,
code: module.code,
map,
name: module.name,
sourcePath: module.path,
source: module.source,
type: module.type,
};
});
const startupModules = modules.filter(module => {
return module.type === 'script' || module.type === 'require';
});
const lazyModules = modules.filter(module => {
return module.type === 'asset' || module.type === 'module';
});
// TODO: Implement RAM groups functionality in Delta Bundler.
return {startupModules, lazyModules, groups: new Map()};
}
async function getAssets(
deltaBundler: DeltaBundler,
options: Options,
): Promise<$ReadOnlyArray<AssetData>> {
const modules = await getAllModules(deltaBundler, options);
const assets = await Promise.all(
modules.map(async module => {
if (module.type === 'asset') {
return await deltaBundler
.getAssetServer()
.getAssetData(module.path, options.platform);
}
return null;
}),
);
return assets.filter(Boolean);
}
async function _build( async function _build(
deltaBundler: DeltaBundler, deltaBundler: DeltaBundler,
options: BuildOptions, options: BuildOptions,
@ -146,4 +209,6 @@ module.exports = {
fullSourceMap, fullSourceMap,
fullSourceMapObject, fullSourceMapObject,
getAllModules, getAllModules,
getAssets,
getRamBundleInfo,
}; };

View File

@ -22,9 +22,12 @@ describe('Serializers', () => {
let deltaBundler; let deltaBundler;
const deltaResponse = { const deltaResponse = {
pre: new Map([[1, {code: 'pre;'}]]), pre: new Map([[1, {type: 'script', code: 'pre;', id: 1, path: '/pre.js'}]]),
post: new Map([[2, {code: 'post;'}]]), post: new Map([[2, {type: 'require', code: 'post;', id: 2, path: '/p'}]]),
delta: new Map([[3, {code: 'module3;'}], [4, {code: 'another;'}]]), delta: new Map([
[3, {type: 'module', code: 'module3;', id: 3, path: '/3.js'}],
[4, {type: 'module', code: 'another;', id: 4, path: '/4.js'}],
]),
inverseDependencies: [], inverseDependencies: [],
reset: true, reset: true,
}; };
@ -45,6 +48,13 @@ describe('Serializers', () => {
}, },
}; };
}, },
getAssetServer() {
return {
async getAssetData(path, platform) {
return {path, platform, assetData: true};
},
};
},
}; };
setCurrentTime(CURRENT_TIME); setCurrentTime(CURRENT_TIME);
@ -133,4 +143,60 @@ describe('Serializers', () => {
await Serializers.getAllModules(deltaBundler, {deltaBundleId: 10}), await Serializers.getAllModules(deltaBundler, {deltaBundleId: 10}),
).toMatchSnapshot(); ).toMatchSnapshot();
}); });
it('should return the RAM bundle info', async () => {
expect(
await Serializers.getRamBundleInfo(deltaBundler, {deltaBundleId: 10}),
).toMatchSnapshot();
getDelta.mockReturnValueOnce(
Promise.resolve({
delta: new Map([
[3, {type: 'module', code: 'modified;', id: 3, path: '/foo/3.js'}],
[7, {type: 'asset', code: 'code', id: 7, path: '/foo/path.png'}],
[8, {type: 'module', code: 'code', id: 8, path: '/foo/8.js'}],
[9, {type: 'asset', code: 'code', id: 9, path: '/foo/path3.png'}],
]),
pre: new Map([
[5, {type: 'script', code: 'more pre;', id: 5, path: '/foo/5.js'}],
]),
post: new Map([
[6, {type: 'require', code: 'bananas;', id: 6, path: '/foo/6.js'}],
[10, {type: 'comment', code: 'bananas;', id: 10, path: '/foo/10.js'}],
]),
inverseDependencies: [],
}),
);
expect(
await Serializers.getRamBundleInfo(deltaBundler, {deltaBundleId: 10}),
).toMatchSnapshot();
});
it('should return the bundle assets', async () => {
expect(
await Serializers.getAllModules(deltaBundler, {deltaBundleId: 10}),
).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: [],
}),
);
expect(
await Serializers.getAssets(deltaBundler, {
deltaBundleId: 10,
platform: 'ios',
}),
).toMatchSnapshot();
});
}); });

View File

@ -32,15 +32,27 @@ exports[`Serializers should return all the bundle modules 1`] = `
Array [ Array [
Object { Object {
"code": "pre;", "code": "pre;",
"id": 1,
"path": "/pre.js",
"type": "script",
}, },
Object { Object {
"code": "module3;", "code": "module3;",
"id": 3,
"path": "/3.js",
"type": "module",
}, },
Object { Object {
"code": "another;", "code": "another;",
"id": 4,
"path": "/4.js",
"type": "module",
}, },
Object { Object {
"code": "post;", "code": "post;",
"id": 2,
"path": "/p",
"type": "require",
}, },
] ]
`; `;
@ -49,6 +61,9 @@ exports[`Serializers should return all the bundle modules 2`] = `
Array [ Array [
Object { Object {
"code": "pre;", "code": "pre;",
"id": 1,
"path": "/pre.js",
"type": "script",
}, },
Object { Object {
"code": "more pre;", "code": "more pre;",
@ -58,6 +73,9 @@ Array [
}, },
Object { Object {
"code": "post;", "code": "post;",
"id": 2,
"path": "/p",
"type": "require",
}, },
Object { Object {
"code": "bananas;", "code": "bananas;",
@ -68,6 +86,278 @@ Array [
] ]
`; `;
exports[`Serializers should return the RAM bundle info 1`] = `
Object {
"groups": Map {},
"lazyModules": Array [
Object {
"code": "module3;",
"id": 3,
"map": Object {
"file": "/3.js",
"mappings": "",
"names": Array [],
"sources": Array [],
"sourcesContent": Array [],
"version": 3,
},
"name": undefined,
"source": undefined,
"sourcePath": "/3.js",
"type": "module",
},
Object {
"code": "another;",
"id": 4,
"map": Object {
"file": "/4.js",
"mappings": "",
"names": Array [],
"sources": Array [],
"sourcesContent": Array [],
"version": 3,
},
"name": undefined,
"source": undefined,
"sourcePath": "/4.js",
"type": "module",
},
],
"startupModules": Array [
Object {
"code": "pre;",
"id": 1,
"map": Object {
"file": "/pre.js",
"mappings": "",
"names": Array [],
"sources": Array [],
"sourcesContent": Array [],
"version": 3,
},
"name": undefined,
"source": undefined,
"sourcePath": "/pre.js",
"type": "script",
},
Object {
"code": "post;",
"id": 2,
"map": Object {
"file": "/p",
"mappings": "",
"names": Array [],
"sources": Array [],
"sourcesContent": Array [],
"version": 3,
},
"name": undefined,
"source": undefined,
"sourcePath": "/p",
"type": "require",
},
],
}
`;
exports[`Serializers should return the RAM bundle info 2`] = `
Object {
"groups": Map {},
"lazyModules": Array [
Object {
"code": "modified;",
"id": 3,
"map": Object {
"file": "/foo/3.js",
"mappings": "",
"names": Array [],
"sources": Array [],
"sourcesContent": Array [],
"version": 3,
},
"name": undefined,
"source": undefined,
"sourcePath": "/foo/3.js",
"type": "module",
},
Object {
"code": "another;",
"id": 4,
"map": Object {
"file": "/4.js",
"mappings": "",
"names": Array [],
"sources": Array [],
"sourcesContent": Array [],
"version": 3,
},
"name": undefined,
"source": undefined,
"sourcePath": "/4.js",
"type": "module",
},
Object {
"code": "code",
"id": 7,
"map": Object {
"file": "/foo/path.png",
"mappings": "",
"names": Array [],
"sources": Array [],
"sourcesContent": Array [],
"version": 3,
},
"name": undefined,
"source": undefined,
"sourcePath": "/foo/path.png",
"type": "asset",
},
Object {
"code": "code",
"id": 8,
"map": Object {
"file": "/foo/8.js",
"mappings": "",
"names": Array [],
"sources": Array [],
"sourcesContent": Array [],
"version": 3,
},
"name": undefined,
"source": undefined,
"sourcePath": "/foo/8.js",
"type": "module",
},
Object {
"code": "code",
"id": 9,
"map": Object {
"file": "/foo/path3.png",
"mappings": "",
"names": Array [],
"sources": Array [],
"sourcesContent": Array [],
"version": 3,
},
"name": undefined,
"source": undefined,
"sourcePath": "/foo/path3.png",
"type": "asset",
},
],
"startupModules": Array [
Object {
"code": "pre;",
"id": 1,
"map": Object {
"file": "/pre.js",
"mappings": "",
"names": Array [],
"sources": Array [],
"sourcesContent": Array [],
"version": 3,
},
"name": undefined,
"source": undefined,
"sourcePath": "/pre.js",
"type": "script",
},
Object {
"code": "more pre;",
"id": 5,
"map": Object {
"file": "/foo/5.js",
"mappings": "",
"names": Array [],
"sources": Array [],
"sourcesContent": Array [],
"version": 3,
},
"name": undefined,
"source": undefined,
"sourcePath": "/foo/5.js",
"type": "script",
},
Object {
"code": "post;",
"id": 2,
"map": Object {
"file": "/p",
"mappings": "",
"names": Array [],
"sources": Array [],
"sourcesContent": Array [],
"version": 3,
},
"name": undefined,
"source": undefined,
"sourcePath": "/p",
"type": "require",
},
Object {
"code": "bananas;",
"id": 6,
"map": Object {
"file": "/foo/6.js",
"mappings": "",
"names": Array [],
"sources": Array [],
"sourcesContent": Array [],
"version": 3,
},
"name": undefined,
"source": undefined,
"sourcePath": "/foo/6.js",
"type": "require",
},
],
}
`;
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`] = ` exports[`Serializers should return the stringified delta bundle 1`] = `
Object { Object {
"bundle": "{\\"id\\":\\"1234\\",\\"pre\\":[[1,\\"pre;\\"]],\\"post\\":[[2,\\"post;\\"]],\\"delta\\":[[3,\\"module3;\\"],[4,\\"another;\\"]],\\"reset\\":true}", "bundle": "{\\"id\\":\\"1234\\",\\"pre\\":[[1,\\"pre;\\"]],\\"post\\":[[2,\\"post;\\"]],\\"delta\\":[[3,\\"module3;\\"],[4,\\"another;\\"]],\\"reset\\":true}",

View File

@ -50,6 +50,10 @@ class DeltaBundler {
this._deltaTransformers = new Map(); this._deltaTransformers = new Map();
} }
getAssetServer() {
return this._bundler.getAssetServer();
}
async getDeltaTransformer( async getDeltaTransformer(
options: Options, options: Options,
): Promise<{deltaTransformer: DeltaTransformer, id: string}> { ): Promise<{deltaTransformer: DeltaTransformer, id: string}> {

View File

@ -47,6 +47,8 @@ import type {
import type {TransformCache} from '../lib/TransformCaching'; import type {TransformCache} from '../lib/TransformCaching';
import type {GlobalTransformCache} from '../lib/GlobalTransformCache'; import type {GlobalTransformCache} from '../lib/GlobalTransformCache';
import type {SourceMap, Symbolicate} from './symbolicate'; import type {SourceMap, Symbolicate} from './symbolicate';
import type {AssetData} from '../AssetServer';
import type {RamBundleInfo} from '../DeltaBundler/Serializers';
const { const {
createActionStartEntry, createActionStartEntry,
@ -348,6 +350,31 @@ class Server {
return bundle; return bundle;
} }
async build(options: BundleOptions): Promise<{code: string, map: string}> {
options = {
...options,
deltaBundleId: null,
};
return {
code: (await Serializers.fullBundle(this._deltaBundler, options)).bundle,
map: await Serializers.fullSourceMap(this._deltaBundler, options),
};
}
async getRamBundleInfo(options: BundleOptions): Promise<RamBundleInfo> {
options = {...options, deltaBundleId: null};
return await Serializers.getRamBundleInfo(this._deltaBundler, options);
}
async getAssets(options: BundleOptions): Promise<$ReadOnlyArray<AssetData>> {
return await Serializers.getAssets(this._deltaBundler, {
...options,
deltaBundleId: null,
});
}
buildBundleFromUrl(reqUrl: string): Promise<Bundle> { buildBundleFromUrl(reqUrl: string): Promise<Bundle> {
const options = this._getOptionsFromUrl(reqUrl); const options = this._getOptionsFromUrl(reqUrl);
return this.buildBundle(options); return this.buildBundle(options);