mirror of https://github.com/status-im/metro.git
metro-bundler: ModuleGraph worker: @format
Reviewed By: davidaurelio Differential Revision: D5658384 fbshipit-source-id: 918017a117e5fb574b3f6801104b4db2708a0eff
This commit is contained in:
parent
72455941ba
commit
6a0efc0853
|
@ -6,11 +6,14 @@
|
|||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @format
|
||||
* @flow
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
/* eslint-disable no-unclear-flowtypes */
|
||||
|
||||
const babel = require('babel-core');
|
||||
|
||||
const MODULE_FACTORY_PARAMETERS = ['global', 'require', 'module', 'exports'];
|
||||
|
@ -26,12 +29,18 @@ function wrapModule(fileAst: Object, dependencyMapName: string): Object {
|
|||
|
||||
function wrapPolyfill(fileAst: Object): Object {
|
||||
const t = babel.types;
|
||||
const factory = functionFromProgram(fileAst.program, POLYFILL_FACTORY_PARAMETERS);
|
||||
const factory = functionFromProgram(
|
||||
fileAst.program,
|
||||
POLYFILL_FACTORY_PARAMETERS,
|
||||
);
|
||||
const iife = t.callExpression(factory, [t.identifier('this')]);
|
||||
return t.file(t.program([t.expressionStatement(iife)]));
|
||||
}
|
||||
|
||||
function functionFromProgram(program: Object, parameters: Array<string>): Object {
|
||||
function functionFromProgram(
|
||||
program: Object,
|
||||
parameters: Array<string>,
|
||||
): Object {
|
||||
const t = babel.types;
|
||||
return t.functionExpression(
|
||||
t.identifier(''),
|
||||
|
|
|
@ -5,7 +5,11 @@
|
|||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @format
|
||||
* @emails oncall+javascript_tools
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const collectDependencies = require('../collect-dependencies');
|
||||
|
@ -24,45 +28,42 @@ describe('dependency collection from ASTs:', () => {
|
|||
}
|
||||
`);
|
||||
|
||||
expect(collectDependencies(ast).dependencies)
|
||||
.toEqual(['b/lib/a', 'do', 'setup/something']);
|
||||
expect(collectDependencies(ast).dependencies).toEqual([
|
||||
'b/lib/a',
|
||||
'do',
|
||||
'setup/something',
|
||||
]);
|
||||
});
|
||||
|
||||
it('supports template literals as arguments', () => {
|
||||
const ast = astFromCode('require(`left-pad`)');
|
||||
|
||||
expect(collectDependencies(ast).dependencies)
|
||||
.toEqual(['left-pad']);
|
||||
expect(collectDependencies(ast).dependencies).toEqual(['left-pad']);
|
||||
});
|
||||
|
||||
it('ignores template literals with interpolations', () => {
|
||||
const ast = astFromCode('require(`left${"-"}pad`)');
|
||||
|
||||
expect(collectDependencies(ast).dependencies)
|
||||
.toEqual([]);
|
||||
expect(collectDependencies(ast).dependencies).toEqual([]);
|
||||
});
|
||||
|
||||
it('ignores tagged template literals', () => {
|
||||
const ast = astFromCode('require(tag`left-pad`)');
|
||||
|
||||
expect(collectDependencies(ast).dependencies)
|
||||
.toEqual([]);
|
||||
expect(collectDependencies(ast).dependencies).toEqual([]);
|
||||
});
|
||||
|
||||
it('exposes a string as `dependencyMapName`', () => {
|
||||
const ast = astFromCode('require("arbitrary")');
|
||||
expect(collectDependencies(ast).dependencyMapName)
|
||||
.toEqual(any(String));
|
||||
expect(collectDependencies(ast).dependencyMapName).toEqual(any(String));
|
||||
});
|
||||
|
||||
it('exposes a string as `dependencyMapName` even without collecting dependencies', () => {
|
||||
const ast = astFromCode('');
|
||||
expect(collectDependencies(ast).dependencyMapName)
|
||||
.toEqual(any(String));
|
||||
expect(collectDependencies(ast).dependencyMapName).toEqual(any(String));
|
||||
});
|
||||
|
||||
it('replaces all required module ID strings with array lookups, keeps the ID as second argument',
|
||||
() => {
|
||||
it('replaces all required module ID strings with array lookups, keeps the ID as second argument', () => {
|
||||
const ast = astFromCode(`
|
||||
const a = require('b/lib/a');
|
||||
const b = require(123);
|
||||
|
@ -74,16 +75,17 @@ describe('dependency collection from ASTs:', () => {
|
|||
|
||||
const {dependencyMapName} = collectDependencies(ast);
|
||||
|
||||
expect(codeFromAst(ast)).toEqual(comparableCode(`
|
||||
expect(codeFromAst(ast)).toEqual(
|
||||
comparableCode(`
|
||||
const a = require(${dependencyMapName}[0], 'b/lib/a');
|
||||
const b = require(123);
|
||||
exports.do = () => require(${dependencyMapName}[1], "do");
|
||||
if (!something) {
|
||||
require(${dependencyMapName}[2], "setup/something");
|
||||
}
|
||||
`));
|
||||
},
|
||||
`),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Dependency collection from optimized ASTs:', () => {
|
||||
|
@ -121,13 +123,15 @@ describe('Dependency collection from optimized ASTs:', () => {
|
|||
|
||||
it('replaces all call signatures inserted by a prior call to `collectDependencies`', () => {
|
||||
forOptimization(ast, names, dependencyMapName);
|
||||
expect(codeFromAst(ast)).toEqual(comparableCode(`
|
||||
expect(codeFromAst(ast)).toEqual(
|
||||
comparableCode(`
|
||||
const a = require(${dependencyMapName}[0]);
|
||||
const b = require(123);
|
||||
exports.do = () => require(${dependencyMapName}[1]);
|
||||
if (!something) {
|
||||
require(${dependencyMapName}[2]);
|
||||
}
|
||||
`));
|
||||
`),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -5,7 +5,11 @@
|
|||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @format
|
||||
* @emails oncall+javascript_tools
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const optimizeModule = require('../optimize-module');
|
||||
|
@ -23,8 +27,7 @@ describe('optimizing JS modules', () => {
|
|||
platform: 'android',
|
||||
postMinifyProcess: x => x,
|
||||
};
|
||||
const originalCode =
|
||||
`if (Platform.OS !== 'android') {
|
||||
const originalCode = `if (Platform.OS !== 'android') {
|
||||
require('arbitrary-dev');
|
||||
} else {
|
||||
__DEV__ ? require('arbitrary-android-dev') : require('arbitrary-android-prod');
|
||||
|
@ -55,12 +58,13 @@ describe('optimizing JS modules', () => {
|
|||
const result = optimizeModule(transformResult, optimizationOptions);
|
||||
optimized = result.details.transformed.default;
|
||||
injectedVars = optimized.code.match(/function\(([^)]*)/)[1].split(',');
|
||||
[, requireName,,, dependencyMapName] = injectedVars;
|
||||
[, requireName, , , dependencyMapName] = injectedVars;
|
||||
});
|
||||
|
||||
it('optimizes code', () => {
|
||||
expect(optimized.code)
|
||||
.toEqual(`__d(function(${injectedVars}){${requireName}(${dependencyMapName}[0])});`);
|
||||
expect(optimized.code).toEqual(
|
||||
`__d(function(${injectedVars}){${requireName}(${dependencyMapName}[0])});`,
|
||||
);
|
||||
});
|
||||
|
||||
it('extracts dependencies', () => {
|
||||
|
@ -72,15 +76,16 @@ describe('optimizing JS modules', () => {
|
|||
const column = optimized.code.lastIndexOf(requireName + '(');
|
||||
const loc = findLast(originalCode, 'require');
|
||||
|
||||
expect(consumer.originalPositionFor({line: 1, column}))
|
||||
.toEqual(objectContaining(loc));
|
||||
expect(consumer.originalPositionFor({line: 1, column})).toEqual(
|
||||
objectContaining(loc),
|
||||
);
|
||||
});
|
||||
|
||||
it('does not extract dependencies for polyfills', () => {
|
||||
const result = optimizeModule(
|
||||
transformResult,
|
||||
{...optimizationOptions, isPolyfill: true},
|
||||
).details;
|
||||
const result = optimizeModule(transformResult, {
|
||||
...optimizationOptions,
|
||||
isPolyfill: true,
|
||||
}).details;
|
||||
expect(result.transformed.default.dependencies).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
@ -90,7 +95,10 @@ describe('optimizing JS modules', () => {
|
|||
beforeEach(() => {
|
||||
postMinifyProcess = fn();
|
||||
optimize = () =>
|
||||
optimizeModule(transformResult, {...optimizationOptions, postMinifyProcess});
|
||||
optimizeModule(transformResult, {
|
||||
...optimizationOptions,
|
||||
postMinifyProcess,
|
||||
});
|
||||
});
|
||||
|
||||
it('passes the result to the provided postprocessing function', () => {
|
||||
|
@ -104,15 +112,17 @@ describe('optimizing JS modules', () => {
|
|||
const code = 'var postprocessed = "code";';
|
||||
const map = {version: 3, mappings: 'postprocessed'};
|
||||
postMinifyProcess.stub.returns({code, map});
|
||||
expect(optimize().details.transformed.default)
|
||||
.toEqual(objectContaining({code, map}));
|
||||
expect(optimize().details.transformed.default).toEqual(
|
||||
objectContaining({code, map}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('passes through non-code data unmodified', () => {
|
||||
const data = {type: 'asset', details: {arbitrary: 'data'}};
|
||||
expect(optimizeModule(JSON.stringify(data), {dev: true, platform: ''}))
|
||||
.toEqual(data);
|
||||
expect(
|
||||
optimizeModule(JSON.stringify(data), {dev: true, platform: ''}),
|
||||
).toEqual(data);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -7,7 +7,9 @@
|
|||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @format
|
||||
* @emails oncall+javascript_tools
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const transformModule = require('../transform-module');
|
||||
|
|
|
@ -5,12 +5,14 @@
|
|||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @format
|
||||
* @emails oncall+javascript_tools
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
jest
|
||||
.mock('fs', () => jest.genMockFromModule('fs'))
|
||||
.mock('mkdirp');
|
||||
jest.mock('fs', () => jest.genMockFromModule('fs')).mock('mkdirp');
|
||||
|
||||
const wrapWorkerFn = require('../wrap-worker-fn');
|
||||
const {dirname} = require('path');
|
||||
|
@ -63,14 +65,20 @@ describe('wrapWorkerFn:', () => {
|
|||
workerFn.stub.yields(null, result);
|
||||
wrapped(infile, outfile, {}, () => {
|
||||
expect(mkdirp.sync).toBeCalledWith(dirname(outfile));
|
||||
expect(fs.writeFileSync).toBeCalledWith(outfile, JSON.stringify(result), 'utf8');
|
||||
expect(fs.writeFileSync).toBeCalledWith(
|
||||
outfile,
|
||||
JSON.stringify(result),
|
||||
'utf8',
|
||||
);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('calls back with any error thrown by `mkdirp.sync`', done => {
|
||||
const error = new Error();
|
||||
mkdirp.sync.mockImplementationOnce(() => { throw error; });
|
||||
mkdirp.sync.mockImplementationOnce(() => {
|
||||
throw error;
|
||||
});
|
||||
wrapped(infile, outfile, {}, e => {
|
||||
expect(e).toBe(error);
|
||||
done();
|
||||
|
@ -79,7 +87,9 @@ describe('wrapWorkerFn:', () => {
|
|||
|
||||
it('calls back with any error thrown by `fs.writeFileSync`', done => {
|
||||
const error = new Error();
|
||||
fs.writeFileSync.mockImplementationOnce(() => { throw error; });
|
||||
fs.writeFileSync.mockImplementationOnce(() => {
|
||||
throw error;
|
||||
});
|
||||
wrapped(infile, outfile, {}, e => {
|
||||
expect(e).toBe(error);
|
||||
done();
|
||||
|
|
|
@ -6,8 +6,10 @@
|
|||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @format
|
||||
* @flow
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const nullthrows = require('fbjs/lib/nullthrows');
|
||||
|
@ -27,8 +29,10 @@ class Replacement {
|
|||
|
||||
isRequireCall(callee, firstArg) {
|
||||
return (
|
||||
callee.type === 'Identifier' && callee.name === 'require' &&
|
||||
firstArg && isLiteralString(firstArg)
|
||||
callee.type === 'Identifier' &&
|
||||
callee.name === 'require' &&
|
||||
firstArg &&
|
||||
isLiteralString(firstArg)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -82,8 +86,9 @@ class ProdReplacement {
|
|||
}
|
||||
|
||||
throw new Error(
|
||||
`${id} is not a known module ID. Existing mappings: ${
|
||||
this.names.map((n, i) => `${i} => ${n}`).join(', ')}`
|
||||
`${id} is not a known module ID. Existing mappings: ${this.names
|
||||
.map((n, i) => `${i} => ${n}`)
|
||||
.join(', ')}`,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -107,11 +112,14 @@ function createMapLookup(dependencyMapIdentifier, propertyIdentifier) {
|
|||
|
||||
function collectDependencies(ast, replacement, dependencyMapIdentifier) {
|
||||
const traversalState = {dependencyMapIdentifier};
|
||||
traverse(ast, {
|
||||
traverse(
|
||||
ast,
|
||||
{
|
||||
Program(path, state) {
|
||||
if (!state.dependencyMapIdentifier) {
|
||||
state.dependencyMapIdentifier =
|
||||
path.scope.generateUidIdentifier('dependencyMap');
|
||||
state.dependencyMapIdentifier = path.scope.generateUidIdentifier(
|
||||
'dependencyMap',
|
||||
);
|
||||
}
|
||||
},
|
||||
CallExpression(path, state) {
|
||||
|
@ -126,7 +134,10 @@ function collectDependencies(ast, replacement, dependencyMapIdentifier) {
|
|||
);
|
||||
}
|
||||
},
|
||||
}, null, traversalState);
|
||||
},
|
||||
null,
|
||||
traversalState,
|
||||
);
|
||||
|
||||
return {
|
||||
dependencies: replacement.getNames(),
|
||||
|
@ -135,14 +146,20 @@ function collectDependencies(ast, replacement, dependencyMapIdentifier) {
|
|||
}
|
||||
|
||||
function isLiteralString(node) {
|
||||
return node.type === 'StringLiteral' ||
|
||||
node.type === 'TemplateLiteral' && node.quasis.length === 1;
|
||||
return (
|
||||
node.type === 'StringLiteral' ||
|
||||
(node.type === 'TemplateLiteral' && node.quasis.length === 1)
|
||||
);
|
||||
}
|
||||
|
||||
exports = module.exports =
|
||||
(ast: AST) => collectDependencies(ast, new Replacement());
|
||||
exports.forOptimization =
|
||||
(ast: AST, names: Array<string>, dependencyMapName?: string) =>
|
||||
const xp = (module.exports = (ast: AST) =>
|
||||
collectDependencies(ast, new Replacement()));
|
||||
|
||||
xp.forOptimization = (
|
||||
ast: AST,
|
||||
names: Array<string>,
|
||||
dependencyMapName?: string,
|
||||
) =>
|
||||
collectDependencies(
|
||||
ast,
|
||||
new ProdReplacement(names),
|
||||
|
|
|
@ -6,21 +6,34 @@
|
|||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @format
|
||||
* @flow
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
/* eslint-disable no-unclear-flowtypes */
|
||||
|
||||
const babelGenerate = require('babel-generator').default;
|
||||
|
||||
function generate(ast: Object, filename: string, sourceCode: string, compact: boolean) {
|
||||
return babelGenerate(ast, {
|
||||
function generate(
|
||||
ast: Object,
|
||||
filename: string,
|
||||
sourceCode: string,
|
||||
compact: boolean,
|
||||
) {
|
||||
return babelGenerate(
|
||||
ast,
|
||||
{
|
||||
comments: false,
|
||||
compact,
|
||||
filename,
|
||||
sourceFileName: filename,
|
||||
sourceMaps: true,
|
||||
sourceMapTarget: filename,
|
||||
}, sourceCode);
|
||||
},
|
||||
sourceCode,
|
||||
);
|
||||
}
|
||||
|
||||
module.exports = generate;
|
||||
|
|
|
@ -6,13 +6,16 @@
|
|||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @format
|
||||
* @flow
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const babel = require('babel-core');
|
||||
const collectDependencies = require('./collect-dependencies');
|
||||
const constantFolding = require('../../JSTransformer/worker/constant-folding').plugin;
|
||||
const constantFolding = require('../../JSTransformer/worker/constant-folding')
|
||||
.plugin;
|
||||
const generate = require('./generate');
|
||||
const inline = require('../../JSTransformer/worker/inline').plugin;
|
||||
const minify = require('../../JSTransformer/worker/minify');
|
||||
|
@ -22,7 +25,6 @@ import type {TransformedSourceFile, TransformResult} from '../types.flow';
|
|||
import type {MappingsMap, SourceMap} from '../../lib/SourceMap';
|
||||
import type {PostMinifyProcess} from '../../Bundler/index.js';
|
||||
|
||||
|
||||
export type OptimizationOptions = {|
|
||||
dev: boolean,
|
||||
isPolyfill?: boolean,
|
||||
|
@ -46,9 +48,14 @@ function optimizeModule(
|
|||
const {postMinifyProcess} = optimizationOptions;
|
||||
|
||||
//$FlowIssue #14545724
|
||||
Object.entries(transformed).forEach(([k, t: TransformResult]: [*, TransformResult]) => {
|
||||
Object.entries(
|
||||
transformed,
|
||||
).forEach(([k, t: TransformResult]: [*, TransformResult]) => {
|
||||
const optimized = optimize(t, file, code, optimizationOptions);
|
||||
const processed = postMinifyProcess({code: optimized.code, map: optimized.map});
|
||||
const processed = postMinifyProcess({
|
||||
code: optimized.code,
|
||||
map: optimized.map,
|
||||
});
|
||||
optimized.code = processed.code;
|
||||
optimized.map = processed.map;
|
||||
result.transformed[k] = optimized;
|
||||
|
@ -102,8 +109,7 @@ function mergeSourceMaps(
|
|||
): MappingsMap {
|
||||
const merged = new sourceMap.SourceMapGenerator();
|
||||
const inputMap = new sourceMap.SourceMapConsumer(originalMap);
|
||||
new sourceMap.SourceMapConsumer(secondMap)
|
||||
.eachMapping(mapping => {
|
||||
new sourceMap.SourceMapConsumer(secondMap).eachMapping(mapping => {
|
||||
const original = inputMap.originalPositionFor({
|
||||
line: mapping.originalLine,
|
||||
column: mapping.originalColumn,
|
||||
|
|
|
@ -6,8 +6,10 @@
|
|||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @format
|
||||
* @flow
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const fs = require('fs');
|
||||
|
|
Loading…
Reference in New Issue