diff --git a/packages/metro-bundler/src/node-haste/DependencyGraph/ResolutionRequest.js b/packages/metro-bundler/src/node-haste/DependencyGraph/ResolutionRequest.js index c1620804..f0f656cb 100644 --- a/packages/metro-bundler/src/node-haste/DependencyGraph/ResolutionRequest.js +++ b/packages/metro-bundler/src/node-haste/DependencyGraph/ResolutionRequest.js @@ -132,11 +132,12 @@ class ResolutionRequest { && !(isRelativeImport(toModuleName) || isAbsolutePath(toModuleName))) { return this._tryResolve( () => Promise.resolve().then(() => this._resolveHasteDependency(fromModule, toModuleName)), - () => this._resolveNodeDependency(fromModule, toModuleName) + () => Promise.resolve().then(() => this._resolveNodeDependency(fromModule, toModuleName)) ).then(cacheResult); } - return this._resolveNodeDependency(fromModule, toModuleName) + return Promise.resolve() + .then(() => this._resolveNodeDependency(fromModule, toModuleName)) .then(cacheResult); } @@ -329,87 +330,90 @@ class ResolutionRequest { ); } - _resolveNodeDependency(fromModule: Module, toModuleName: string): Promise { - return Promise.resolve().then(() => { - if (isRelativeImport(toModuleName) || isAbsolutePath(toModuleName)) { - return this._resolveFileOrDir(fromModule, toModuleName); - } - const realModuleName = this._redirectRequire(fromModule, toModuleName); - // exclude - if (realModuleName === false) { - return this._loadAsFile( - ResolutionRequest.emptyModule, - fromModule, - toModuleName, + _resolveNodeDependency(fromModule: Module, toModuleName: string): Module { + if (isRelativeImport(toModuleName) || isAbsolutePath(toModuleName)) { + return this._resolveFileOrDir(fromModule, toModuleName); + } + const realModuleName = this._redirectRequire(fromModule, toModuleName); + // exclude + if (realModuleName === false) { + return this._loadAsFile( + ResolutionRequest.emptyModule, + fromModule, + toModuleName, + ); + } + + if (isRelativeImport(realModuleName) || isAbsolutePath(realModuleName)) { + // derive absolute path /.../node_modules/fromModuleDir/realModuleName + const fromModuleParentIdx = fromModule.path.lastIndexOf('node_modules' + path.sep) + 13; + const fromModuleDir = fromModule.path.slice( + 0, + fromModule.path.indexOf(path.sep, fromModuleParentIdx), + ); + const absPath = path.join(fromModuleDir, realModuleName); + return this._resolveFileOrDir(fromModule, absPath); + } + + const searchQueue = []; + for (let currDir = path.dirname(fromModule.path); + currDir !== '.' && currDir !== realPath.parse(fromModule.path).root; + currDir = path.dirname(currDir)) { + const searchPath = path.join(currDir, 'node_modules'); + if (this._dirExists(searchPath)) { + searchQueue.push( + path.join(searchPath, realModuleName) ); } + } - if (isRelativeImport(realModuleName) || isAbsolutePath(realModuleName)) { - // derive absolute path /.../node_modules/fromModuleDir/realModuleName - const fromModuleParentIdx = fromModule.path.lastIndexOf('node_modules' + path.sep) + 13; - const fromModuleDir = fromModule.path.slice( - 0, - fromModule.path.indexOf(path.sep, fromModuleParentIdx), - ); - const absPath = path.join(fromModuleDir, realModuleName); - return this._resolveFileOrDir(fromModule, absPath); + if (this._extraNodeModules) { + const {_extraNodeModules} = this; + const bits = toModuleName.split(path.sep); + const packageName = bits[0]; + if (_extraNodeModules[packageName]) { + bits[0] = _extraNodeModules[packageName]; + searchQueue.push(path.join.apply(path, bits)); } + } - const searchQueue = []; - for (let currDir = path.dirname(fromModule.path); - currDir !== '.' && currDir !== realPath.parse(fromModule.path).root; - currDir = path.dirname(currDir)) { - const searchPath = path.join(currDir, 'node_modules'); - if (this._dirExists(searchPath)) { - searchQueue.push( - path.join(searchPath, realModuleName) - ); - } + for (let i = 0; i < searchQueue.length; ++i) { + const resolvedModule = this._tryResolveNodeDep(searchQueue[i], fromModule, toModuleName); + if (resolvedModule != null) { + return resolvedModule; } + } - if (this._extraNodeModules) { - const {_extraNodeModules} = this; - const bits = toModuleName.split(path.sep); - const packageName = bits[0]; - if (_extraNodeModules[packageName]) { - bits[0] = _extraNodeModules[packageName]; - searchQueue.push(path.join.apply(path, bits)); - } + const hint = searchQueue.length ? ' or in these directories:' : ''; + throw new UnableToResolveError( + fromModule, + toModuleName, + `Module does not exist in the module map${hint}\n` + + searchQueue.map(searchPath => ` ${path.dirname(searchPath)}\n`).join(', ') + '\n' + + `This might be related to https://github.com/facebook/react-native/issues/4968\n` + + `To resolve try the following:\n` + + ` 1. Clear watchman watches: \`watchman watch-del-all\`.\n` + + ` 2. Delete the \`node_modules\` folder: \`rm -rf node_modules && npm install\`.\n` + + ' 3. Reset packager cache: `rm -fr $TMPDIR/react-*` or `npm start -- --reset-cache`.' + ); + } + + /** + * This is written as a separate function because "try..catch" blocks cause + * the entire surrounding function to be deoptimized. + */ + _tryResolveNodeDep(searchPath: string, fromModule: Module, toModuleName: string): ?Module { + try { + return tryResolveSync( + () => this._loadAsFile(searchPath, fromModule, toModuleName), + () => this._loadAsDir(searchPath, fromModule, toModuleName), + ); + } catch (error) { + if (error.type !== 'UnableToResolveError') { + throw error; } - - let p = Promise.reject(new UnableToResolveError(fromModule, toModuleName)); - searchQueue.forEach(potentialModulePath => { - p = this._tryResolve( - () => this._tryResolve( - () => p, - () => Promise.resolve().then( - () => this._loadAsFile(potentialModulePath, fromModule, toModuleName), - ), - ), - () => Promise.resolve().then( - () => this._loadAsDir(potentialModulePath, fromModule, toModuleName), - ), - ); - }); - - return p.catch(error => { - if (error.type !== 'UnableToResolveError') { - throw error; - } - const hint = searchQueue.length ? ' or in these directories:' : ''; - throw new UnableToResolveError( - fromModule, - toModuleName, - `Module does not exist in the module map${hint}\n` + - searchQueue.map(searchPath => ` ${path.dirname(searchPath)}\n`).join(', ') + '\n' + - `This might be related to https://github.com/facebook/react-native/issues/4968\n` + - `To resolve try the following:\n` + - ` 1. Clear watchman watches: \`watchman watch-del-all\`.\n` + - ` 2. Delete the \`node_modules\` folder: \`rm -rf node_modules && npm install\`.\n` + - ' 3. Reset packager cache: `rm -fr $TMPDIR/react-*` or `npm start -- --reset-cache`.' - ); - }); - }); + return null; + } } _loadAsFile(potentialModulePath: string, fromModule: Module, toModule: string): Module {