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 addParamsToDefineCall = require('../lib/addParamsToDefineCall');
|
||||
const createModuleIdFactory = require('../lib/createModuleIdFactory');
|
||||
const crypto = require('crypto');
|
||||
const defaults = require('../defaults');
|
||||
const getPreludeCode = require('../lib/getPreludeCode');
|
||||
const nullthrows = require('fbjs/lib/nullthrows');
|
||||
|
||||
const {wrapModule} = require('./Serializers/helpers/js');
|
||||
const {EventEmitter} = require('events');
|
||||
|
||||
import type Bundler from '../Bundler';
|
||||
|
@ -444,27 +443,10 @@ class DeltaTransformer extends EventEmitter {
|
|||
): Promise<[number, ?DeltaEntry]> {
|
||||
const name = this._dependencyGraph.getHasteName(edge.path);
|
||||
|
||||
const dependencyPairs = edge ? edge.dependencies : new Map();
|
||||
|
||||
let wrappedCode;
|
||||
|
||||
// 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 wrappedCode = wrapModule(edge, {
|
||||
createModuleIdFn: this._getModuleId,
|
||||
dev: transformOptions.dev,
|
||||
});
|
||||
|
||||
const {code, map} = transformOptions.minify
|
||||
? 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 = () => {
|
||||
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