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;
}
getAssetServer(): AssetServer {
return this._assetServer;
}
end() {
this._transformer.kill();
/* $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');
import type {AssetData} from '../AssetServer';
import type {BundleOptions} from '../Server';
import type {MappingsMap} from '../lib/SourceMap';
import type {ModuleTransportLike} from '../shared/types.flow';
import type DeltaBundler, {Options as BuildOptions} from './';
import type {DeltaEntry, DeltaTransformResponse} from './DeltaTransformer';
@ -25,6 +27,14 @@ export type Options = BundleOptions & {
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
* returns a string representation for any specific type of bundle, which can
@ -115,7 +125,7 @@ async function fullBundle(
async function getAllModules(
deltaBundler: DeltaBundler,
options: Options,
): Promise<Array<DeltaEntry>> {
): Promise<$ReadOnlyArray<DeltaEntry>> {
const {id, delta} = await _build(deltaBundler, {
...options,
wrapModules: true,
@ -126,6 +136,59 @@ async function 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(
deltaBundler: DeltaBundler,
options: BuildOptions,
@ -146,4 +209,6 @@ module.exports = {
fullSourceMap,
fullSourceMapObject,
getAllModules,
getAssets,
getRamBundleInfo,
};

View File

@ -22,9 +22,12 @@ describe('Serializers', () => {
let deltaBundler;
const deltaResponse = {
pre: new Map([[1, {code: 'pre;'}]]),
post: new Map([[2, {code: 'post;'}]]),
delta: new Map([[3, {code: 'module3;'}], [4, {code: 'another;'}]]),
pre: new Map([[1, {type: 'script', code: 'pre;', id: 1, path: '/pre.js'}]]),
post: new Map([[2, {type: 'require', code: 'post;', id: 2, path: '/p'}]]),
delta: new Map([
[3, {type: 'module', code: 'module3;', id: 3, path: '/3.js'}],
[4, {type: 'module', code: 'another;', id: 4, path: '/4.js'}],
]),
inverseDependencies: [],
reset: true,
};
@ -45,6 +48,13 @@ describe('Serializers', () => {
},
};
},
getAssetServer() {
return {
async getAssetData(path, platform) {
return {path, platform, assetData: true};
},
};
},
};
setCurrentTime(CURRENT_TIME);
@ -133,4 +143,60 @@ describe('Serializers', () => {
await Serializers.getAllModules(deltaBundler, {deltaBundleId: 10}),
).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 [
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",
},
]
`;
@ -49,6 +61,9 @@ exports[`Serializers should return all the bundle modules 2`] = `
Array [
Object {
"code": "pre;",
"id": 1,
"path": "/pre.js",
"type": "script",
},
Object {
"code": "more pre;",
@ -58,6 +73,9 @@ Array [
},
Object {
"code": "post;",
"id": 2,
"path": "/p",
"type": "require",
},
Object {
"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`] = `
Object {
"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();
}
getAssetServer() {
return this._bundler.getAssetServer();
}
async getDeltaTransformer(
options: Options,
): Promise<{deltaTransformer: DeltaTransformer, id: string}> {

View File

@ -47,6 +47,8 @@ import type {
import type {TransformCache} from '../lib/TransformCaching';
import type {GlobalTransformCache} from '../lib/GlobalTransformCache';
import type {SourceMap, Symbolicate} from './symbolicate';
import type {AssetData} from '../AssetServer';
import type {RamBundleInfo} from '../DeltaBundler/Serializers';
const {
createActionStartEntry,
@ -348,6 +350,31 @@ class Server {
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> {
const options = this._getOptionsFromUrl(reqUrl);
return this.buildBundle(options);