mirror of https://github.com/status-im/metro.git
Add new plainJSSerializer that uses directly the Graph object
Reviewed By: mjesun Differential Revision: D7211546 fbshipit-source-id: 7e6a0a0123f46a9037ecae845d29daea43e1ebed
This commit is contained in:
parent
a4afdcb2e8
commit
3ac0bb47d9
|
@ -12,13 +12,12 @@
|
||||||
|
|
||||||
const DeltaCalculator = require('./DeltaCalculator');
|
const DeltaCalculator = require('./DeltaCalculator');
|
||||||
|
|
||||||
const addParamsToDefineCall = require('../lib/addParamsToDefineCall');
|
|
||||||
const createModuleIdFactory = require('../lib/createModuleIdFactory');
|
const createModuleIdFactory = require('../lib/createModuleIdFactory');
|
||||||
const crypto = require('crypto');
|
const crypto = require('crypto');
|
||||||
const defaults = require('../defaults');
|
const defaults = require('../defaults');
|
||||||
const getPreludeCode = require('../lib/getPreludeCode');
|
const getPreludeCode = require('../lib/getPreludeCode');
|
||||||
const nullthrows = require('fbjs/lib/nullthrows');
|
|
||||||
|
|
||||||
|
const {wrapModule} = require('./Serializers/helpers/js');
|
||||||
const {EventEmitter} = require('events');
|
const {EventEmitter} = require('events');
|
||||||
|
|
||||||
import type Bundler from '../Bundler';
|
import type Bundler from '../Bundler';
|
||||||
|
@ -444,27 +443,10 @@ class DeltaTransformer extends EventEmitter {
|
||||||
): Promise<[number, ?DeltaEntry]> {
|
): Promise<[number, ?DeltaEntry]> {
|
||||||
const name = this._dependencyGraph.getHasteName(edge.path);
|
const name = this._dependencyGraph.getHasteName(edge.path);
|
||||||
|
|
||||||
const dependencyPairs = edge ? edge.dependencies : new Map();
|
const wrappedCode = wrapModule(edge, {
|
||||||
|
createModuleIdFn: this._getModuleId,
|
||||||
let wrappedCode;
|
dev: transformOptions.dev,
|
||||||
|
});
|
||||||
// Get the absolute path of each of the module dependencies from the
|
|
||||||
// dependency edges. The module dependencies ensure correct order, while
|
|
||||||
// the dependency edges do not ensure the same order between rebuilds.
|
|
||||||
const dependencies = Array.from(edge.dependencies.keys()).map(dependency =>
|
|
||||||
nullthrows(dependencyPairs.get(dependency)),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (edge.output.type !== 'script') {
|
|
||||||
wrappedCode = this._addDependencyMap({
|
|
||||||
code: edge.output.code,
|
|
||||||
dependencies,
|
|
||||||
name,
|
|
||||||
path: edge.path,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
wrappedCode = edge.output.code;
|
|
||||||
}
|
|
||||||
|
|
||||||
const {code, map} = transformOptions.minify
|
const {code, map} = transformOptions.minify
|
||||||
? await this._bundler.minifyModule(
|
? await this._bundler.minifyModule(
|
||||||
|
@ -490,35 +472,6 @@ class DeltaTransformer extends EventEmitter {
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Function to add the mapping object between local module ids and
|
|
||||||
* actual bundle module ids for dependencies. This way, we can do the path
|
|
||||||
* replacements on require() calls on transformers (since local ids do not
|
|
||||||
* change between bundles).
|
|
||||||
*/
|
|
||||||
_addDependencyMap({
|
|
||||||
code,
|
|
||||||
dependencies,
|
|
||||||
name,
|
|
||||||
path,
|
|
||||||
}: {
|
|
||||||
code: string,
|
|
||||||
dependencies: $ReadOnlyArray<string>,
|
|
||||||
name: string,
|
|
||||||
path: string,
|
|
||||||
}): string {
|
|
||||||
const moduleId = this._getModuleId(path);
|
|
||||||
const params = [moduleId, dependencies.map(this._getModuleId)];
|
|
||||||
|
|
||||||
// Add the module name as the last parameter (to make it easier to do
|
|
||||||
// requires by name when debugging).
|
|
||||||
if (this._bundleOptions.dev) {
|
|
||||||
params.push(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
return addParamsToDefineCall(code, ...params);
|
|
||||||
}
|
|
||||||
|
|
||||||
_onFileChange = () => {
|
_onFileChange = () => {
|
||||||
this.emit('change');
|
this.emit('change');
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,119 @@
|
||||||
|
/**
|
||||||
|
* 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';
|
||||||
|
|
||||||
|
const createModuleIdFactory = require('../../../lib/createModuleIdFactory');
|
||||||
|
const plainJSBundle = require('../plainJSBundle');
|
||||||
|
|
||||||
|
const polyfill = {
|
||||||
|
output: {
|
||||||
|
type: 'script',
|
||||||
|
code: '__d(function() {/* code for polyfill */});',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const fooModule = {
|
||||||
|
path: 'foo',
|
||||||
|
dependencies: new Map([['./bar', 'bar']]),
|
||||||
|
output: {code: '__d(function() {/* code for foo */});'},
|
||||||
|
};
|
||||||
|
|
||||||
|
const barModule = {
|
||||||
|
path: 'bar',
|
||||||
|
dependencies: new Map(),
|
||||||
|
output: {code: '__d(function() {/* code for bar */});'},
|
||||||
|
};
|
||||||
|
|
||||||
|
it('should serialize a very simple bundle', () => {
|
||||||
|
expect(
|
||||||
|
plainJSBundle(
|
||||||
|
'foo',
|
||||||
|
[polyfill],
|
||||||
|
{
|
||||||
|
dependencies: new Map([['foo', fooModule], ['bar', barModule]]),
|
||||||
|
entryPoints: ['foo'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
createModuleIdFn: path => path,
|
||||||
|
dev: true,
|
||||||
|
runBeforeMainModule: [],
|
||||||
|
runModule: true,
|
||||||
|
sourceMapUrl: 'http://localhost/bundle.map',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
).toEqual(
|
||||||
|
[
|
||||||
|
'__d(function() {/* code for polyfill */});',
|
||||||
|
'__d(function() {/* code for foo */},"foo",["bar"],"foo");',
|
||||||
|
'__d(function() {/* code for bar */},"bar",[],"bar");',
|
||||||
|
'require("foo");',
|
||||||
|
'//# sourceMappingURL=http://localhost/bundle.map',
|
||||||
|
].join('\n'),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add runBeforeMainModule statements if found in the graph', () => {
|
||||||
|
expect(
|
||||||
|
plainJSBundle(
|
||||||
|
'foo',
|
||||||
|
[polyfill],
|
||||||
|
{
|
||||||
|
dependencies: new Map([['foo', fooModule], ['bar', barModule]]),
|
||||||
|
entryPoints: ['foo'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
createModuleIdFn: path => path,
|
||||||
|
dev: true,
|
||||||
|
runBeforeMainModule: ['bar', 'non-existant'],
|
||||||
|
runModule: true,
|
||||||
|
sourceMapUrl: 'http://localhost/bundle.map',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
).toEqual(
|
||||||
|
[
|
||||||
|
'__d(function() {/* code for polyfill */});',
|
||||||
|
'__d(function() {/* code for foo */},"foo",["bar"],"foo");',
|
||||||
|
'__d(function() {/* code for bar */},"bar",[],"bar");',
|
||||||
|
'require("bar");',
|
||||||
|
'require("foo");',
|
||||||
|
'//# sourceMappingURL=http://localhost/bundle.map',
|
||||||
|
].join('\n'),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle numeric module ids', () => {
|
||||||
|
expect(
|
||||||
|
plainJSBundle(
|
||||||
|
'foo',
|
||||||
|
[polyfill],
|
||||||
|
{
|
||||||
|
dependencies: new Map([['foo', fooModule], ['bar', barModule]]),
|
||||||
|
entryPoints: ['foo'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
createModuleIdFn: createModuleIdFactory(),
|
||||||
|
dev: true,
|
||||||
|
runBeforeMainModule: ['bar', 'non-existant'],
|
||||||
|
runModule: true,
|
||||||
|
sourceMapUrl: 'http://localhost/bundle.map',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
).toEqual(
|
||||||
|
[
|
||||||
|
'__d(function() {/* code for polyfill */});',
|
||||||
|
'__d(function() {/* code for foo */},0,[1],"foo");',
|
||||||
|
'__d(function() {/* code for bar */},1,[],"bar");',
|
||||||
|
'require(1);',
|
||||||
|
'require(0);',
|
||||||
|
'//# sourceMappingURL=http://localhost/bundle.map',
|
||||||
|
].join('\n'),
|
||||||
|
);
|
||||||
|
});
|
|
@ -0,0 +1,75 @@
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
* @flow
|
||||||
|
* @format
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const createModuleIdFactory = require('../../../../lib/createModuleIdFactory');
|
||||||
|
|
||||||
|
const {wrapModule} = require('../js');
|
||||||
|
|
||||||
|
let myModule;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
myModule = {
|
||||||
|
path: '/root/foo.js',
|
||||||
|
dependencies: new Map([['bar', '/bar'], ['baz', '/baz']]),
|
||||||
|
inverseDependencies: new Set(),
|
||||||
|
output: {
|
||||||
|
code: '__d(function() { console.log("foo") });',
|
||||||
|
map: [],
|
||||||
|
source: '',
|
||||||
|
type: 'module',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('wrapModule()', () => {
|
||||||
|
it('Should wrap a module in nondev mode', () => {
|
||||||
|
expect(
|
||||||
|
wrapModule(myModule, {
|
||||||
|
createModuleIdFn: createModuleIdFactory(),
|
||||||
|
dev: false,
|
||||||
|
}),
|
||||||
|
).toEqual('__d(function() { console.log("foo") },0,[1,2]);');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should wrap a module in dev mode', () => {
|
||||||
|
expect(
|
||||||
|
wrapModule(myModule, {
|
||||||
|
createModuleIdFn: createModuleIdFactory(),
|
||||||
|
dev: true,
|
||||||
|
}),
|
||||||
|
).toEqual('__d(function() { console.log("foo") },0,[1,2],"foo.js");');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not wrap a script', () => {
|
||||||
|
myModule.output.type = 'script';
|
||||||
|
|
||||||
|
expect(
|
||||||
|
wrapModule(myModule, {
|
||||||
|
createModuleIdFn: createModuleIdFactory(),
|
||||||
|
dev: true,
|
||||||
|
}),
|
||||||
|
).toEqual(myModule.output.code);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should use custom createModuleIdFn param', () => {
|
||||||
|
// Just use a createModuleIdFn that returns the same path.
|
||||||
|
expect(
|
||||||
|
wrapModule(myModule, {
|
||||||
|
createModuleIdFn: path => path,
|
||||||
|
dev: false,
|
||||||
|
}),
|
||||||
|
).toEqual(
|
||||||
|
'__d(function() { console.log("foo") },"/root/foo.js",["/bar","/baz"]);',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
|
@ -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 addParamsToDefineCall = require('../../../lib/addParamsToDefineCall');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
import type {DependencyEdge} from '../../traverseDependencies';
|
||||||
|
|
||||||
|
export type Options = {
|
||||||
|
+createModuleIdFn: string => number | string,
|
||||||
|
+dev: boolean,
|
||||||
|
};
|
||||||
|
|
||||||
|
function wrapModule(module: DependencyEdge, options: Options) {
|
||||||
|
if (module.output.type === 'script') {
|
||||||
|
return module.output.code;
|
||||||
|
}
|
||||||
|
|
||||||
|
const moduleId = options.createModuleIdFn(module.path);
|
||||||
|
const params = [
|
||||||
|
moduleId,
|
||||||
|
Array.from(module.dependencies.values()).map(options.createModuleIdFn),
|
||||||
|
];
|
||||||
|
|
||||||
|
// Add the module name as the last parameter (to make it easier to do
|
||||||
|
// requires by name when debugging).
|
||||||
|
// TODO (t26853986): Switch this to use the relative file path (once we have
|
||||||
|
// as single project root).
|
||||||
|
if (options.dev) {
|
||||||
|
params.push(path.basename(module.path));
|
||||||
|
}
|
||||||
|
|
||||||
|
return addParamsToDefineCall(module.output.code, ...params);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
wrapModule,
|
||||||
|
};
|
|
@ -0,0 +1,63 @@
|
||||||
|
/**
|
||||||
|
* 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 {wrapModule} = require('./helpers/js');
|
||||||
|
|
||||||
|
import type {Graph} from '../DeltaCalculator';
|
||||||
|
import type {DependencyEdge} from '../traverseDependencies';
|
||||||
|
|
||||||
|
type Options = {|
|
||||||
|
createModuleIdFn: string => number | string,
|
||||||
|
+dev: boolean,
|
||||||
|
+runBeforeMainModule: $ReadOnlyArray<string>,
|
||||||
|
+runModule: boolean,
|
||||||
|
+sourceMapUrl: ?string,
|
||||||
|
|};
|
||||||
|
|
||||||
|
function plainJSBundle(
|
||||||
|
entryPoint: string,
|
||||||
|
pre: $ReadOnlyArray<DependencyEdge>,
|
||||||
|
graph: Graph,
|
||||||
|
options: Options,
|
||||||
|
): string {
|
||||||
|
const output = [];
|
||||||
|
|
||||||
|
for (const module of pre) {
|
||||||
|
output.push(wrapModule(module, options));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const module of graph.dependencies.values()) {
|
||||||
|
output.push(wrapModule(module, options));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const path of options.runBeforeMainModule) {
|
||||||
|
if (graph.dependencies.has(path)) {
|
||||||
|
output.push(
|
||||||
|
`require(${JSON.stringify(options.createModuleIdFn(path))});`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.runModule && graph.dependencies.has(entryPoint)) {
|
||||||
|
output.push(
|
||||||
|
`require(${JSON.stringify(options.createModuleIdFn(entryPoint))});`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.sourceMapUrl) {
|
||||||
|
output.push(`//# sourceMappingURL=${options.sourceMapUrl}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return output.join('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = plainJSBundle;
|
|
@ -0,0 +1,37 @@
|
||||||
|
/**
|
||||||
|
* 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 {fromRawMappings} = require('metro-source-map');
|
||||||
|
|
||||||
|
import type {Graph} from '../DeltaCalculator';
|
||||||
|
import type {DependencyEdge} from '../traverseDependencies';
|
||||||
|
|
||||||
|
function fullSourceMap(
|
||||||
|
pre: $ReadOnlyArray<DependencyEdge>,
|
||||||
|
graph: Graph,
|
||||||
|
options: {|+excludeSource: boolean|},
|
||||||
|
): string {
|
||||||
|
const modules = pre.concat(...graph.dependencies.values());
|
||||||
|
|
||||||
|
const modulesWithMaps = modules.map(module => {
|
||||||
|
return {
|
||||||
|
...module.output,
|
||||||
|
path: module.path,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return fromRawMappings(modulesWithMaps).toString(undefined, {
|
||||||
|
excludeSource: options.excludeSource,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = fullSourceMap;
|
Loading…
Reference in New Issue