mirror of https://github.com/status-im/metro.git
metro: introduce asyncRequire function
Reviewed By: davidaurelio Differential Revision: D6498107 fbshipit-source-id: a9c4ab634e60f19b7058205eddcd248f57f63500
This commit is contained in:
parent
636c0ed5c9
commit
2ecf6c9450
|
@ -56,13 +56,11 @@ it('collects asynchronous dependencies', () => {
|
||||||
const {dependencies, dependencyMapName} = collectDependencies(ast);
|
const {dependencies, dependencyMapName} = collectDependencies(ast);
|
||||||
expect(dependencies).toEqual([
|
expect(dependencies).toEqual([
|
||||||
{name: 'some/async/module', isAsync: true},
|
{name: 'some/async/module', isAsync: true},
|
||||||
{name: 'BundleSegments', isAsync: false},
|
{name: 'asyncRequire', isAsync: false},
|
||||||
]);
|
]);
|
||||||
expect(codeFromAst(ast)).toEqual(
|
expect(codeFromAst(ast)).toEqual(
|
||||||
comparableCode(`
|
comparableCode(`
|
||||||
require(${dependencyMapName}[1], "BundleSegments").loadForModule(${dependencyMapName}[0]).then(function () {
|
require(${dependencyMapName}[1], "asyncRequire")(${dependencyMapName}[0]).then(foo => {});
|
||||||
return require(${dependencyMapName}[0], "some/async/module");
|
|
||||||
}).then(foo => {});
|
|
||||||
`),
|
`),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -75,14 +73,12 @@ it('collects mixed dependencies as being sync', () => {
|
||||||
const {dependencies, dependencyMapName} = collectDependencies(ast);
|
const {dependencies, dependencyMapName} = collectDependencies(ast);
|
||||||
expect(dependencies).toEqual([
|
expect(dependencies).toEqual([
|
||||||
{name: 'some/async/module', isAsync: false},
|
{name: 'some/async/module', isAsync: false},
|
||||||
{name: 'BundleSegments', isAsync: false},
|
{name: 'asyncRequire', isAsync: false},
|
||||||
]);
|
]);
|
||||||
expect(codeFromAst(ast)).toEqual(
|
expect(codeFromAst(ast)).toEqual(
|
||||||
comparableCode(`
|
comparableCode(`
|
||||||
const a = require(${dependencyMapName}[0], "some/async/module");
|
const a = require(${dependencyMapName}[0], "some/async/module");
|
||||||
require(${dependencyMapName}[1], "BundleSegments").loadForModule(${dependencyMapName}[0]).then(function () {
|
require(${dependencyMapName}[1], "asyncRequire")(${dependencyMapName}[0]).then(foo => {});
|
||||||
return require(${dependencyMapName}[0], "some/async/module");
|
|
||||||
}).then(foo => {});
|
|
||||||
`),
|
`),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -95,13 +91,11 @@ it('collects mixed dependencies as being sync; reverse order', () => {
|
||||||
const {dependencies, dependencyMapName} = collectDependencies(ast);
|
const {dependencies, dependencyMapName} = collectDependencies(ast);
|
||||||
expect(dependencies).toEqual([
|
expect(dependencies).toEqual([
|
||||||
{name: 'some/async/module', isAsync: false},
|
{name: 'some/async/module', isAsync: false},
|
||||||
{name: 'BundleSegments', isAsync: false},
|
{name: 'asyncRequire', isAsync: false},
|
||||||
]);
|
]);
|
||||||
expect(codeFromAst(ast)).toEqual(
|
expect(codeFromAst(ast)).toEqual(
|
||||||
comparableCode(`
|
comparableCode(`
|
||||||
require(${dependencyMapName}[1], "BundleSegments").loadForModule(${dependencyMapName}[0]).then(function () {
|
require(${dependencyMapName}[1], "asyncRequire")(${dependencyMapName}[0]).then(foo => {});
|
||||||
return require(${dependencyMapName}[0], "some/async/module");
|
|
||||||
}).then(foo => {});
|
|
||||||
const a = require(${dependencyMapName}[0], "some/async/module");
|
const a = require(${dependencyMapName}[0], "some/async/module");
|
||||||
`),
|
`),
|
||||||
);
|
);
|
||||||
|
|
|
@ -23,7 +23,7 @@ const DEP_MAP_NAME = 'arbitrary';
|
||||||
const DEPS = [
|
const DEPS = [
|
||||||
{name: 'b/lib/a', isAsync: false},
|
{name: 'b/lib/a', isAsync: false},
|
||||||
{name: 'do', isAsync: false},
|
{name: 'do', isAsync: false},
|
||||||
{name: 'BundleSegments', isAsync: false},
|
{name: 'asyncRequire', isAsync: false},
|
||||||
{name: 'some/async/module', isAsync: true},
|
{name: 'some/async/module', isAsync: true},
|
||||||
{name: 'setup/something', isAsync: false},
|
{name: 'setup/something', isAsync: false},
|
||||||
];
|
];
|
||||||
|
@ -32,9 +32,7 @@ it('returns dependencies from the transformed AST', () => {
|
||||||
const ast = astFromCode(`
|
const ast = astFromCode(`
|
||||||
const a = require(${DEP_MAP_NAME}[0], 'b/lib/a');
|
const a = require(${DEP_MAP_NAME}[0], 'b/lib/a');
|
||||||
exports.do = () => require(${DEP_MAP_NAME}[1], "do");
|
exports.do = () => require(${DEP_MAP_NAME}[1], "do");
|
||||||
require(${DEP_MAP_NAME}[2], "BundleSegments").loadForModule(${DEP_MAP_NAME}[3]).then(function () {
|
require(${DEP_MAP_NAME}[2], "asyncRequire")(${DEP_MAP_NAME}[3]).then(foo => {});
|
||||||
return require(${DEP_MAP_NAME}[3], "some/async/module");
|
|
||||||
}).then(foo => {});
|
|
||||||
if (!something) {
|
if (!something) {
|
||||||
require(${DEP_MAP_NAME}[4], "setup/something");
|
require(${DEP_MAP_NAME}[4], "setup/something");
|
||||||
}
|
}
|
||||||
|
@ -45,9 +43,7 @@ it('returns dependencies from the transformed AST', () => {
|
||||||
comparableCode(`
|
comparableCode(`
|
||||||
const a = require(${DEP_MAP_NAME}[0]);
|
const a = require(${DEP_MAP_NAME}[0]);
|
||||||
exports.do = () => require(${DEP_MAP_NAME}[1]);
|
exports.do = () => require(${DEP_MAP_NAME}[1]);
|
||||||
require(${DEP_MAP_NAME}[2]).loadForModule(${DEP_MAP_NAME}[3]).then(function () {
|
require(${DEP_MAP_NAME}[2])(${DEP_MAP_NAME}[3]).then(foo => {});
|
||||||
return require(${DEP_MAP_NAME}[3]);
|
|
||||||
}).then(foo => {});
|
|
||||||
if (!something) {
|
if (!something) {
|
||||||
require(${DEP_MAP_NAME}[4]);
|
require(${DEP_MAP_NAME}[4]);
|
||||||
}
|
}
|
||||||
|
@ -66,20 +62,16 @@ it('strips unused dependencies and translates require() calls', () => {
|
||||||
|
|
||||||
it('strips unused dependencies and translates loadForModule() calls', () => {
|
it('strips unused dependencies and translates loadForModule() calls', () => {
|
||||||
const ast = astFromCode(`
|
const ast = astFromCode(`
|
||||||
require(${DEP_MAP_NAME}[2], "BundleSegments").loadForModule(${DEP_MAP_NAME}[3]).then(function () {
|
require(${DEP_MAP_NAME}[2], "asyncRequire")(${DEP_MAP_NAME}[3]).then(foo => {});
|
||||||
return require(${DEP_MAP_NAME}[3], "some/async/module");
|
|
||||||
}).then(foo => {});
|
|
||||||
`);
|
`);
|
||||||
const dependencies = optimizeDependencies(ast, DEPS, DEP_MAP_NAME);
|
const dependencies = optimizeDependencies(ast, DEPS, DEP_MAP_NAME);
|
||||||
expect(dependencies).toEqual([
|
expect(dependencies).toEqual([
|
||||||
{name: 'BundleSegments', isAsync: false},
|
{name: 'asyncRequire', isAsync: false},
|
||||||
{name: 'some/async/module', isAsync: true},
|
{name: 'some/async/module', isAsync: true},
|
||||||
]);
|
]);
|
||||||
expect(codeFromAst(ast)).toEqual(
|
expect(codeFromAst(ast)).toEqual(
|
||||||
comparableCode(`
|
comparableCode(`
|
||||||
require(${DEP_MAP_NAME}[0]).loadForModule(${DEP_MAP_NAME}[1]).then(function () {
|
require(${DEP_MAP_NAME}[0])(${DEP_MAP_NAME}[1]).then(foo => {});
|
||||||
return require(${DEP_MAP_NAME}[1]);
|
|
||||||
}).then(foo => {});
|
|
||||||
`),
|
`),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -87,27 +79,23 @@ it('strips unused dependencies and translates loadForModule() calls', () => {
|
||||||
it('strips unused dependencies and translates loadForModule() calls; different ordering', () => {
|
it('strips unused dependencies and translates loadForModule() calls; different ordering', () => {
|
||||||
const ast = astFromCode(`
|
const ast = astFromCode(`
|
||||||
require(${DEP_MAP_NAME}[0], 'something/else');
|
require(${DEP_MAP_NAME}[0], 'something/else');
|
||||||
require(${DEP_MAP_NAME}[2], "BundleSegments").loadForModule(${DEP_MAP_NAME}[1]).then(function () {
|
require(${DEP_MAP_NAME}[2], "asyncRequire")(${DEP_MAP_NAME}[1]).then(foo => {});
|
||||||
return require(${DEP_MAP_NAME}[1], "some/async/module");
|
|
||||||
}).then(foo => {});
|
|
||||||
`);
|
`);
|
||||||
const deps = [
|
const deps = [
|
||||||
{name: 'something/else', isAsync: false},
|
{name: 'something/else', isAsync: false},
|
||||||
{name: 'some/async/module', isAsync: true},
|
{name: 'some/async/module', isAsync: true},
|
||||||
{name: 'BundleSegments', isAsync: false},
|
{name: 'asyncRequire', isAsync: false},
|
||||||
];
|
];
|
||||||
const dependencies = optimizeDependencies(ast, deps, DEP_MAP_NAME);
|
const dependencies = optimizeDependencies(ast, deps, DEP_MAP_NAME);
|
||||||
expect(dependencies).toEqual([
|
expect(dependencies).toEqual([
|
||||||
{name: 'something/else', isAsync: false},
|
{name: 'something/else', isAsync: false},
|
||||||
{name: 'BundleSegments', isAsync: false},
|
{name: 'asyncRequire', isAsync: false},
|
||||||
{name: 'some/async/module', isAsync: true},
|
{name: 'some/async/module', isAsync: true},
|
||||||
]);
|
]);
|
||||||
expect(codeFromAst(ast)).toEqual(
|
expect(codeFromAst(ast)).toEqual(
|
||||||
comparableCode(`
|
comparableCode(`
|
||||||
require(${DEP_MAP_NAME}[0]);
|
require(${DEP_MAP_NAME}[0]);
|
||||||
require(${DEP_MAP_NAME}[1]).loadForModule(${DEP_MAP_NAME}[2]).then(function () {
|
require(${DEP_MAP_NAME}[1])(${DEP_MAP_NAME}[2]).then(foo => {});
|
||||||
return require(${DEP_MAP_NAME}[2]);
|
|
||||||
}).then(foo => {});
|
|
||||||
`),
|
`),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
|
@ -54,8 +54,7 @@ function collectDependencies(ast: Ast): CollectedDependencies {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (node.callee.type === 'Import') {
|
if (node.callee.type === 'Import') {
|
||||||
const reqNode = processImportCall(context, path, node, depMapIdent);
|
processImportCall(context, path, node, depMapIdent);
|
||||||
visited.add(reqNode);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (isRequireCall(node.callee)) {
|
if (isRequireCall(node.callee)) {
|
||||||
|
@ -81,24 +80,17 @@ function processImportCall(context, path, node, depMapIdent) {
|
||||||
const index = assignDependencyIndex(context, name, 'import');
|
const index = assignDependencyIndex(context, name, 'import');
|
||||||
const mapLookup = createDepMapLookup(depMapIdent, index);
|
const mapLookup = createDepMapLookup(depMapIdent, index);
|
||||||
const newImport = makeAsyncRequire({
|
const newImport = makeAsyncRequire({
|
||||||
REQUIRE_ARGS: createRequireArgs(mapLookup, nameLiteral),
|
|
||||||
MODULE_ID: mapLookup,
|
MODULE_ID: mapLookup,
|
||||||
BUNDLE_SEGMENTS_PATH: {
|
ASYNC_REQUIRE_PATH: {type: 'StringLiteral', value: 'asyncRequire'},
|
||||||
type: 'StringLiteral',
|
|
||||||
value: 'BundleSegments',
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
path.replaceWith(newImport);
|
path.replaceWith(newImport);
|
||||||
// This is the inner require() call. We return it so it
|
|
||||||
// gets marked as already visited.
|
|
||||||
return newImport.expression.arguments[0].body.body[0].argument;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function processRequireCall(context, node, depMapIdent) {
|
function processRequireCall(context, node, depMapIdent) {
|
||||||
const [nameLiteral, name] = getModuleNameFromCallArgs(node);
|
const [nameLiteral, name] = getModuleNameFromCallArgs(node);
|
||||||
const index = assignDependencyIndex(context, name, 'require');
|
const index = assignDependencyIndex(context, name, 'require');
|
||||||
const mapLookup = createDepMapLookup(depMapIdent, index);
|
const mapLookup = createDepMapLookup(depMapIdent, index);
|
||||||
node.arguments = createRequireArgs(mapLookup, nameLiteral);
|
node.arguments = [mapLookup, nameLiteral];
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,15 +146,9 @@ function createDepMapLookup(depMapIndent, index: number) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const makeAsyncRequire = babelTemplate(
|
const makeAsyncRequire = babelTemplate(
|
||||||
`require(BUNDLE_SEGMENTS_PATH).loadForModule(MODULE_ID).then(
|
`require(ASYNC_REQUIRE_PATH)(MODULE_ID)`,
|
||||||
function() { return require(REQUIRE_ARGS); }
|
|
||||||
)`,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
function createRequireArgs(mapLookup, moduleNameLiteral) {
|
|
||||||
return [mapLookup, moduleNameLiteral];
|
|
||||||
}
|
|
||||||
|
|
||||||
function invalidRequireOf(type, node) {
|
function invalidRequireOf(type, node) {
|
||||||
return new InvalidRequireCallError(
|
return new InvalidRequireCallError(
|
||||||
`Calls to ${type}() expect exactly 1 string literal argument, ` +
|
`Calls to ${type}() expect exactly 1 string literal argument, ` +
|
||||||
|
|
Loading…
Reference in New Issue