mirror of https://github.com/status-im/metro.git
Add ramGroups and preloadedModules support when creating RAM bundles
Reviewed By: davidaurelio Differential Revision: D6250307 fbshipit-source-id: b7143fa31ded9fcaa28025f05b9d28013361ea0e
This commit is contained in:
parent
91f724d69d
commit
98518c9fff
|
@ -876,6 +876,36 @@ class Bundler {
|
||||||
return transform || {inlineRequires: false};
|
return transform || {inlineRequires: false};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the options needed to create a RAM bundle.
|
||||||
|
*/
|
||||||
|
async getRamOptions(
|
||||||
|
entryFile: string,
|
||||||
|
options: {dev: boolean, platform: ?string},
|
||||||
|
getDependencies: string => Promise<Array<string>>,
|
||||||
|
): Promise<{|
|
||||||
|
+preloadedModules: {[string]: true},
|
||||||
|
+ramGroups: Array<string>,
|
||||||
|
|}> {
|
||||||
|
if (!this._getTransformOptions) {
|
||||||
|
return {
|
||||||
|
preloadedModules: {},
|
||||||
|
ramGroups: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const {preloadedModules, ramGroups} = await this._getTransformOptions(
|
||||||
|
[entryFile],
|
||||||
|
{dev: options.dev, hot: true, platform: options.platform},
|
||||||
|
getDependencies,
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
preloadedModules: preloadedModules || {},
|
||||||
|
ramGroups: ramGroups || [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Helper method to return the global transform options that are kept in the
|
* Helper method to return the global transform options that are kept in the
|
||||||
* Bundler.
|
* Bundler.
|
||||||
|
|
|
@ -36,7 +36,7 @@ export type PlatformRemoteFileMap = {
|
||||||
type SubTree<T: ModuleTransportLike> = (
|
type SubTree<T: ModuleTransportLike> = (
|
||||||
moduleTransport: T,
|
moduleTransport: T,
|
||||||
moduleTransportsByPath: Map<string, T>,
|
moduleTransportsByPath: Map<string, T>,
|
||||||
) => Generator<number, void, void>;
|
) => Iterable<number>;
|
||||||
|
|
||||||
const assetPropertyBlacklist = new Set(['files', 'fileSystemLocation', 'path']);
|
const assetPropertyBlacklist = new Set(['files', 'fileSystemLocation', 'path']);
|
||||||
|
|
||||||
|
|
|
@ -153,6 +153,36 @@ class DeltaTransformer extends EventEmitter {
|
||||||
return this._deltaCalculator.end();
|
return this._deltaCalculator.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a function that can be used to calculate synchronously the
|
||||||
|
* transitive dependencies of any given file within the dependency graph.
|
||||||
|
**/
|
||||||
|
async getDependenciesFn() {
|
||||||
|
if (!this._deltaCalculator.getDependencyEdges().size) {
|
||||||
|
// If by any means the dependency graph has not been initialized, call
|
||||||
|
// getDelta() to initialize it.
|
||||||
|
await this._getDelta();
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._getDependencies;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getRamOptions(
|
||||||
|
entryFile: string,
|
||||||
|
options: {dev: boolean, platform: ?string},
|
||||||
|
): Promise<{|
|
||||||
|
+preloadedModules: {[string]: true},
|
||||||
|
+ramGroups: $ReadOnlyArray<string>,
|
||||||
|
|}> {
|
||||||
|
const getDependenciesFn = await this.getDependenciesFn();
|
||||||
|
|
||||||
|
return await this._bundler.getRamOptions(
|
||||||
|
entryFile,
|
||||||
|
options,
|
||||||
|
async (path: string) => Array.from(getDependenciesFn(path)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main method to calculate the bundle delta. It returns a DeltaResult,
|
* Main method to calculate the bundle delta. It returns a DeltaResult,
|
||||||
* which contain the source code of the modified and added modules and the
|
* which contain the source code of the modified and added modules and the
|
||||||
|
@ -226,6 +256,44 @@ class DeltaTransformer extends EventEmitter {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_getDependencies = (path: string): Set<string> => {
|
||||||
|
const dependencies = this._getDeps(
|
||||||
|
path,
|
||||||
|
this._deltaCalculator.getDependencyEdges(),
|
||||||
|
new Set(),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Remove the main entry point, since this method only returns the
|
||||||
|
// dependencies.
|
||||||
|
dependencies.delete(path);
|
||||||
|
|
||||||
|
return dependencies;
|
||||||
|
};
|
||||||
|
|
||||||
|
_getDeps(
|
||||||
|
path: string,
|
||||||
|
edges: DependencyEdges,
|
||||||
|
deps: Set<string>,
|
||||||
|
): Set<string> {
|
||||||
|
if (deps.has(path)) {
|
||||||
|
return deps;
|
||||||
|
}
|
||||||
|
|
||||||
|
const edge = edges.get(path);
|
||||||
|
|
||||||
|
if (!edge) {
|
||||||
|
return deps;
|
||||||
|
}
|
||||||
|
|
||||||
|
deps.add(path);
|
||||||
|
|
||||||
|
for (const [, dependencyPath] of edge.dependencies) {
|
||||||
|
this._getDeps(dependencyPath, edges, deps);
|
||||||
|
}
|
||||||
|
|
||||||
|
return deps;
|
||||||
|
}
|
||||||
|
|
||||||
async _getPrepend(
|
async _getPrepend(
|
||||||
transformOptions: JSTransformerOptions,
|
transformOptions: JSTransformerOptions,
|
||||||
dependencyEdges: DependencyEdges,
|
dependencyEdges: DependencyEdges,
|
||||||
|
|
|
@ -15,13 +15,17 @@
|
||||||
const DeltaPatcher = require('./DeltaPatcher');
|
const DeltaPatcher = require('./DeltaPatcher');
|
||||||
|
|
||||||
const {fromRawMappings} = require('../Bundler/source-map');
|
const {fromRawMappings} = require('../Bundler/source-map');
|
||||||
|
const {createRamBundleGroups} = require('../Bundler/util');
|
||||||
|
|
||||||
import type {AssetData} from '../AssetServer';
|
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 {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 DeltaTransformer, {
|
||||||
|
DeltaEntry,
|
||||||
|
DeltaTransformResponse,
|
||||||
|
} from './DeltaTransformer';
|
||||||
|
|
||||||
export type Options = BundleOptions & {
|
export type Options = BundleOptions & {
|
||||||
deltaBundleId: ?string,
|
deltaBundleId: ?string,
|
||||||
|
@ -30,8 +34,8 @@ export type Options = BundleOptions & {
|
||||||
export type RamModule = ModuleTransportLike;
|
export type RamModule = ModuleTransportLike;
|
||||||
|
|
||||||
export type RamBundleInfo = {
|
export type RamBundleInfo = {
|
||||||
startupModules: $ReadOnlyArray<ModuleTransportLike>,
|
startupModules: $ReadOnlyArray<RamModule>,
|
||||||
lazyModules: $ReadOnlyArray<ModuleTransportLike>,
|
lazyModules: $ReadOnlyArray<RamModule>,
|
||||||
groups: Map<number, Set<number>>,
|
groups: Map<number, Set<number>>,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -140,33 +144,82 @@ async function getRamBundleInfo(
|
||||||
deltaBundler: DeltaBundler,
|
deltaBundler: DeltaBundler,
|
||||||
options: Options,
|
options: Options,
|
||||||
): Promise<RamBundleInfo> {
|
): Promise<RamBundleInfo> {
|
||||||
let modules = await getAllModules(deltaBundler, options);
|
const {id, delta, deltaTransformer} = await _build(deltaBundler, {
|
||||||
|
...options,
|
||||||
|
wrapModules: true,
|
||||||
|
});
|
||||||
|
|
||||||
modules = modules.map(module => {
|
const modules = DeltaPatcher.get(id)
|
||||||
const map = fromRawMappings([module]).toMap(module.path, {
|
.applyDelta(delta)
|
||||||
excludeSource: options.excludeSource,
|
.getAllModules()
|
||||||
|
.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,
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
const {
|
||||||
id: module.id,
|
preloadedModules,
|
||||||
code: module.code,
|
ramGroups,
|
||||||
map,
|
} = await deltaTransformer.getRamOptions(options.entryFile, {
|
||||||
name: module.name,
|
dev: options.dev,
|
||||||
sourcePath: module.path,
|
platform: options.platform,
|
||||||
source: module.source,
|
|
||||||
type: module.type,
|
|
||||||
};
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const startupModules = modules.filter(module => {
|
const startupModules = [];
|
||||||
return module.type === 'script' || module.type === 'require';
|
const lazyModules = [];
|
||||||
});
|
modules.forEach(module => {
|
||||||
const lazyModules = modules.filter(module => {
|
if (preloadedModules.hasOwnProperty(module.sourcePath)) {
|
||||||
return module.type === 'asset' || module.type === 'module';
|
startupModules.push(module);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (module.type === 'script' || module.type === 'require') {
|
||||||
|
startupModules.push(module);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (module.type === 'asset' || module.type === 'module') {
|
||||||
|
lazyModules.push(module);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO: Implement RAM groups functionality in Delta Bundler.
|
const getDependencies = await deltaTransformer.getDependenciesFn();
|
||||||
return {startupModules, lazyModules, groups: new Map()};
|
|
||||||
|
const groups = createRamBundleGroups(
|
||||||
|
ramGroups,
|
||||||
|
lazyModules,
|
||||||
|
(module: RamModule, dependenciesByPath: Map<string, RamModule>) => {
|
||||||
|
const deps = getDependencies(module.sourcePath);
|
||||||
|
const output = new Set();
|
||||||
|
|
||||||
|
for (const dependency of deps) {
|
||||||
|
const module = dependenciesByPath.get(dependency);
|
||||||
|
|
||||||
|
if (module) {
|
||||||
|
output.add(module.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
startupModules,
|
||||||
|
lazyModules,
|
||||||
|
groups,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getAssets(
|
async function getAssets(
|
||||||
|
@ -192,7 +245,11 @@ async function getAssets(
|
||||||
async function _build(
|
async function _build(
|
||||||
deltaBundler: DeltaBundler,
|
deltaBundler: DeltaBundler,
|
||||||
options: BuildOptions,
|
options: BuildOptions,
|
||||||
): Promise<{id: string, delta: DeltaTransformResponse}> {
|
): Promise<{
|
||||||
|
id: string,
|
||||||
|
delta: DeltaTransformResponse,
|
||||||
|
deltaTransformer: DeltaTransformer,
|
||||||
|
}> {
|
||||||
const {deltaTransformer, id} = await deltaBundler.getDeltaTransformer(
|
const {deltaTransformer, id} = await deltaBundler.getDeltaTransformer(
|
||||||
options,
|
options,
|
||||||
);
|
);
|
||||||
|
@ -200,6 +257,7 @@ async function _build(
|
||||||
return {
|
return {
|
||||||
id,
|
id,
|
||||||
delta: await deltaTransformer.getDelta(),
|
delta: await deltaTransformer.getDelta(),
|
||||||
|
deltaTransformer,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,8 @@ const CURRENT_TIME = 1482363367000;
|
||||||
describe('Serializers', () => {
|
describe('Serializers', () => {
|
||||||
const OriginalDate = global.Date;
|
const OriginalDate = global.Date;
|
||||||
const getDelta = jest.fn();
|
const getDelta = jest.fn();
|
||||||
|
const getDependenciesFn = jest.fn();
|
||||||
|
const getRamOptions = jest.fn();
|
||||||
let deltaBundler;
|
let deltaBundler;
|
||||||
|
|
||||||
const deltaResponse = {
|
const deltaResponse = {
|
||||||
|
@ -38,6 +40,13 @@ describe('Serializers', () => {
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
getDelta.mockReturnValueOnce(Promise.resolve(deltaResponse));
|
getDelta.mockReturnValueOnce(Promise.resolve(deltaResponse));
|
||||||
|
getDependenciesFn.mockReturnValue(Promise.resolve(() => new Set()));
|
||||||
|
getRamOptions.mockReturnValue(
|
||||||
|
Promise.resolve({
|
||||||
|
preloadedModules: {},
|
||||||
|
ramGroups: [],
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
deltaBundler = {
|
deltaBundler = {
|
||||||
async getDeltaTransformer() {
|
async getDeltaTransformer() {
|
||||||
|
@ -45,6 +54,8 @@ describe('Serializers', () => {
|
||||||
id: '1234',
|
id: '1234',
|
||||||
deltaTransformer: {
|
deltaTransformer: {
|
||||||
getDelta,
|
getDelta,
|
||||||
|
getDependenciesFn,
|
||||||
|
getRamOptions,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@ -173,6 +184,49 @@ describe('Serializers', () => {
|
||||||
).toMatchSnapshot();
|
).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should use the preloadedModules and ramGroup configs to build a RAM bundle', async () => {
|
||||||
|
getDelta.mockReset();
|
||||||
|
getDependenciesFn.mockReset();
|
||||||
|
|
||||||
|
getDelta.mockReturnValue(
|
||||||
|
Promise.resolve({
|
||||||
|
delta: new Map([
|
||||||
|
[3, {type: 'module', code: 'code', id: 3, path: '/foo/3.js'}],
|
||||||
|
[4, {type: 'module', code: 'code', id: 4, path: '/foo/4.js'}],
|
||||||
|
[5, {type: 'module', code: 'code', id: 5, path: '/foo/5.js'}],
|
||||||
|
[6, {type: 'module', code: 'code', id: 6, path: '/foo/6.js'}],
|
||||||
|
]),
|
||||||
|
pre: new Map([
|
||||||
|
[7, {type: 'script', code: 'more pre;', id: 7, path: '/foo/7.js'}],
|
||||||
|
]),
|
||||||
|
post: new Map([
|
||||||
|
[8, {type: 'require', code: 'bananas;', id: 8, path: '/foo/8.js'}],
|
||||||
|
]),
|
||||||
|
inverseDependencies: [],
|
||||||
|
reset: 1,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
getRamOptions.mockReturnValue(
|
||||||
|
Promise.resolve({
|
||||||
|
preloadedModules: {'/foo/3.js': true},
|
||||||
|
ramGroups: ['/foo/5.js'],
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
getDependenciesFn.mockReturnValue(
|
||||||
|
Promise.resolve(path => {
|
||||||
|
expect(path).toBe('/foo/5.js');
|
||||||
|
|
||||||
|
return new Set(['/foo/6.js']);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
await Serializers.getRamBundleInfo(deltaBundler, {deltaBundleId: 10}),
|
||||||
|
).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
it('should return the bundle assets', async () => {
|
it('should return the bundle assets', async () => {
|
||||||
expect(
|
expect(
|
||||||
await Serializers.getAllModules(deltaBundler, {deltaBundleId: 10}),
|
await Serializers.getAllModules(deltaBundler, {deltaBundleId: 10}),
|
||||||
|
|
|
@ -371,3 +371,113 @@ Object {
|
||||||
"numModifiedFiles": 2,
|
"numModifiedFiles": 2,
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`Serializers should use the preloadedModules and ramGroup configs to build a RAM bundle 1`] = `
|
||||||
|
Object {
|
||||||
|
"groups": Map {
|
||||||
|
5 => Set {
|
||||||
|
6,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"lazyModules": Array [
|
||||||
|
Object {
|
||||||
|
"code": "code",
|
||||||
|
"id": 4,
|
||||||
|
"map": Object {
|
||||||
|
"file": "/foo/4.js",
|
||||||
|
"mappings": "",
|
||||||
|
"names": Array [],
|
||||||
|
"sources": Array [],
|
||||||
|
"sourcesContent": Array [],
|
||||||
|
"version": 3,
|
||||||
|
},
|
||||||
|
"name": undefined,
|
||||||
|
"source": undefined,
|
||||||
|
"sourcePath": "/foo/4.js",
|
||||||
|
"type": "module",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"code": "code",
|
||||||
|
"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": "module",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"code": "code",
|
||||||
|
"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": "module",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"startupModules": Array [
|
||||||
|
Object {
|
||||||
|
"code": "more pre;",
|
||||||
|
"id": 7,
|
||||||
|
"map": Object {
|
||||||
|
"file": "/foo/7.js",
|
||||||
|
"mappings": "",
|
||||||
|
"names": Array [],
|
||||||
|
"sources": Array [],
|
||||||
|
"sourcesContent": Array [],
|
||||||
|
"version": 3,
|
||||||
|
},
|
||||||
|
"name": undefined,
|
||||||
|
"source": undefined,
|
||||||
|
"sourcePath": "/foo/7.js",
|
||||||
|
"type": "script",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"code": "code",
|
||||||
|
"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": "bananas;",
|
||||||
|
"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": "require",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
Loading…
Reference in New Issue