diff --git a/packages/metro-bundler/src/JSTransformer/worker/__tests__/extract-dependencies-test.js b/packages/metro-bundler/src/JSTransformer/worker/__tests__/extract-dependencies-test.js index 730f8e37..fdec5a1f 100644 --- a/packages/metro-bundler/src/JSTransformer/worker/__tests__/extract-dependencies-test.js +++ b/packages/metro-bundler/src/JSTransformer/worker/__tests__/extract-dependencies-test.js @@ -30,6 +30,14 @@ describe('Dependency extraction:', () => { expect(dependencyOffsets).toEqual([8, 46, 147, 203]); }); + it('can extract calls to require.async', () => { + const code = `foo(); + require.async('bar').then(() => {});`; + const {dependencies, dependencyOffsets} = extractDependencies(code); + expect(dependencies).toEqual(['bar']); + expect(dependencyOffsets).toEqual([27]); + }); + it('does not extract require method calls', () => { const code = ` require('a'); diff --git a/packages/metro-bundler/src/JSTransformer/worker/extract-dependencies.js b/packages/metro-bundler/src/JSTransformer/worker/extract-dependencies.js index 1ec56b21..b38dc448 100644 --- a/packages/metro-bundler/src/JSTransformer/worker/extract-dependencies.js +++ b/packages/metro-bundler/src/JSTransformer/worker/extract-dependencies.js @@ -33,19 +33,34 @@ function extractDependencies(code: string) { const dependencies = new Set(); const dependencyOffsets = []; + function pushDependency(nodeArgs) { + const arg = nodeArgs[0]; + if (nodeArgs.length != 1 || arg.type !== 'StringLiteral') { + throw new Error('require() must have a single string literal argument'); + } + dependencyOffsets.push(arg.start); + dependencies.add(arg.value); + } + babel.traverse(ast, { CallExpression(path) { const node = path.node; const callee = node.callee; if (callee.type === 'Identifier' && callee.name === 'require') { - const arg = node.arguments[0]; - if (arg == null || arg.type !== 'StringLiteral') { - throw new Error( - 'require() must have a single string literal argument', - ); - } - dependencyOffsets.push(arg.start); - dependencies.add(arg.value); + pushDependency(node.arguments); + } + if (callee.type !== 'MemberExpression') { + return; + } + const obj = callee.object; + const prop = callee.property; + if ( + obj.type === 'Identifier' && + obj.name === 'require' && + !callee.computed && + prop.name === 'async' + ) { + pushDependency(node.arguments); } }, }); diff --git a/packages/metro-bundler/src/Resolver/polyfills/require.js b/packages/metro-bundler/src/Resolver/polyfills/require.js index b2382a2b..bb4aa595 100644 --- a/packages/metro-bundler/src/Resolver/polyfills/require.js +++ b/packages/metro-bundler/src/Resolver/polyfills/require.js @@ -110,6 +110,10 @@ function require(moduleId: ModuleID | VerboseModuleNameForDev) { : guardedLoadModule(moduleIdReallyIsNumber, module); } +require.async = function(moduleId: ModuleID | VerboseModuleNameForDev) { + return Promise.resolve().then(() => require(moduleId)); +}; + let inGuard = false; function guardedLoadModule(moduleId: ModuleID, module) { if (!inGuard && global.ErrorUtils) { diff --git a/packages/metro-bundler/src/integration_tests/__tests__/__snapshots__/basic_bundle-test.js.snap b/packages/metro-bundler/src/integration_tests/__tests__/__snapshots__/basic_bundle-test.js.snap index 1dd374d3..fd5c89ed 100644 --- a/packages/metro-bundler/src/integration_tests/__tests__/__snapshots__/basic_bundle-test.js.snap +++ b/packages/metro-bundler/src/integration_tests/__tests__/__snapshots__/basic_bundle-test.js.snap @@ -57,6 +57,12 @@ function _require(moduleId) { return module && module.isInitialized ? module.exports : guardedLoadModule(moduleIdReallyIsNumber, module); } +_require.async = function (moduleId) { + return Promise.resolve().then(function () { + return _require(moduleId); + }); +}; + var inGuard = false; function guardedLoadModule(moduleId, module) { if (!inGuard && global.ErrorUtils) { @@ -324,6 +330,12 @@ function _require(moduleId) { return module && module.isInitialized ? module.exports : guardedLoadModule(moduleIdReallyIsNumber, module); } +_require.async = function (moduleId) { + return Promise.resolve().then(function () { + return _require(moduleId); + }); +}; + var inGuard = false; function guardedLoadModule(moduleId, module) { if (!inGuard && global.ErrorUtils) {