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};
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* Bundler.
|
||||
|
|
|
@ -36,7 +36,7 @@ export type PlatformRemoteFileMap = {
|
|||
type SubTree<T: ModuleTransportLike> = (
|
||||
moduleTransport: T,
|
||||
moduleTransportsByPath: Map<string, T>,
|
||||
) => Generator<number, void, void>;
|
||||
) => Iterable<number>;
|
||||
|
||||
const assetPropertyBlacklist = new Set(['files', 'fileSystemLocation', 'path']);
|
||||
|
||||
|
|
|
@ -153,6 +153,36 @@ class DeltaTransformer extends EventEmitter {
|
|||
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,
|
||||
* 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(
|
||||
transformOptions: JSTransformerOptions,
|
||||
dependencyEdges: DependencyEdges,
|
||||
|
|
|
@ -15,13 +15,17 @@
|
|||
const DeltaPatcher = require('./DeltaPatcher');
|
||||
|
||||
const {fromRawMappings} = require('../Bundler/source-map');
|
||||
const {createRamBundleGroups} = require('../Bundler/util');
|
||||
|
||||
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';
|
||||
import type DeltaTransformer, {
|
||||
DeltaEntry,
|
||||
DeltaTransformResponse,
|
||||
} from './DeltaTransformer';
|
||||
|
||||
export type Options = BundleOptions & {
|
||||
deltaBundleId: ?string,
|
||||
|
@ -30,8 +34,8 @@ export type Options = BundleOptions & {
|
|||
export type RamModule = ModuleTransportLike;
|
||||
|
||||
export type RamBundleInfo = {
|
||||
startupModules: $ReadOnlyArray<ModuleTransportLike>,
|
||||
lazyModules: $ReadOnlyArray<ModuleTransportLike>,
|
||||
startupModules: $ReadOnlyArray<RamModule>,
|
||||
lazyModules: $ReadOnlyArray<RamModule>,
|
||||
groups: Map<number, Set<number>>,
|
||||
};
|
||||
|
||||
|
@ -140,33 +144,82 @@ async function getRamBundleInfo(
|
|||
deltaBundler: DeltaBundler,
|
||||
options: Options,
|
||||
): Promise<RamBundleInfo> {
|
||||
let modules = await getAllModules(deltaBundler, options);
|
||||
const {id, delta, deltaTransformer} = await _build(deltaBundler, {
|
||||
...options,
|
||||
wrapModules: true,
|
||||
});
|
||||
|
||||
modules = modules.map(module => {
|
||||
const map = fromRawMappings([module]).toMap(module.path, {
|
||||
excludeSource: options.excludeSource,
|
||||
const modules = DeltaPatcher.get(id)
|
||||
.applyDelta(delta)
|
||||
.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 {
|
||||
id: module.id,
|
||||
code: module.code,
|
||||
map,
|
||||
name: module.name,
|
||||
sourcePath: module.path,
|
||||
source: module.source,
|
||||
type: module.type,
|
||||
};
|
||||
const {
|
||||
preloadedModules,
|
||||
ramGroups,
|
||||
} = await deltaTransformer.getRamOptions(options.entryFile, {
|
||||
dev: options.dev,
|
||||
platform: options.platform,
|
||||
});
|
||||
|
||||
const startupModules = modules.filter(module => {
|
||||
return module.type === 'script' || module.type === 'require';
|
||||
});
|
||||
const lazyModules = modules.filter(module => {
|
||||
return module.type === 'asset' || module.type === 'module';
|
||||
const startupModules = [];
|
||||
const lazyModules = [];
|
||||
modules.forEach(module => {
|
||||
if (preloadedModules.hasOwnProperty(module.sourcePath)) {
|
||||
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.
|
||||
return {startupModules, lazyModules, groups: new Map()};
|
||||
const getDependencies = await deltaTransformer.getDependenciesFn();
|
||||
|
||||
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(
|
||||
|
@ -192,7 +245,11 @@ async function getAssets(
|
|||
async function _build(
|
||||
deltaBundler: DeltaBundler,
|
||||
options: BuildOptions,
|
||||
): Promise<{id: string, delta: DeltaTransformResponse}> {
|
||||
): Promise<{
|
||||
id: string,
|
||||
delta: DeltaTransformResponse,
|
||||
deltaTransformer: DeltaTransformer,
|
||||
}> {
|
||||
const {deltaTransformer, id} = await deltaBundler.getDeltaTransformer(
|
||||
options,
|
||||
);
|
||||
|
@ -200,6 +257,7 @@ async function _build(
|
|||
return {
|
||||
id,
|
||||
delta: await deltaTransformer.getDelta(),
|
||||
deltaTransformer,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,8 @@ const CURRENT_TIME = 1482363367000;
|
|||
describe('Serializers', () => {
|
||||
const OriginalDate = global.Date;
|
||||
const getDelta = jest.fn();
|
||||
const getDependenciesFn = jest.fn();
|
||||
const getRamOptions = jest.fn();
|
||||
let deltaBundler;
|
||||
|
||||
const deltaResponse = {
|
||||
|
@ -38,6 +40,13 @@ describe('Serializers', () => {
|
|||
|
||||
beforeEach(() => {
|
||||
getDelta.mockReturnValueOnce(Promise.resolve(deltaResponse));
|
||||
getDependenciesFn.mockReturnValue(Promise.resolve(() => new Set()));
|
||||
getRamOptions.mockReturnValue(
|
||||
Promise.resolve({
|
||||
preloadedModules: {},
|
||||
ramGroups: [],
|
||||
}),
|
||||
);
|
||||
|
||||
deltaBundler = {
|
||||
async getDeltaTransformer() {
|
||||
|
@ -45,6 +54,8 @@ describe('Serializers', () => {
|
|||
id: '1234',
|
||||
deltaTransformer: {
|
||||
getDelta,
|
||||
getDependenciesFn,
|
||||
getRamOptions,
|
||||
},
|
||||
};
|
||||
},
|
||||
|
@ -173,6 +184,49 @@ describe('Serializers', () => {
|
|||
).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 () => {
|
||||
expect(
|
||||
await Serializers.getAllModules(deltaBundler, {deltaBundleId: 10}),
|
||||
|
|
|
@ -371,3 +371,113 @@ Object {
|
|||
"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