From 190dc69c89b1d5ab3eb0e0c023a127752573acab Mon Sep 17 00:00:00 2001 From: Brian White Date: Fri, 13 Jan 2017 05:02:45 -0500 Subject: [PATCH 01/10] benchmark: add parameter for module benchmark MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: /~https://github.com/nodejs/node/pull/10789 Reviewed-By: James M Snell Reviewed-By: Michaël Zasso Reviewed-By: Michael Dawson Reviewed-By: Matteo Collina Reviewed-By: Benjamin Gruenbaum --- benchmark/module/module-loader.js | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/benchmark/module/module-loader.js b/benchmark/module/module-loader.js index a175533c7bbc6e..090f7b78549a4d 100644 --- a/benchmark/module/module-loader.js +++ b/benchmark/module/module-loader.js @@ -8,7 +8,8 @@ var benchmarkDirectory = path.join(tmpDirectory, 'nodejs-benchmark-module'); var bench = common.createBenchmark(main, { thousands: [50], - fullPath: ['true', 'false'] + fullPath: ['true', 'false'], + useCache: ['true', 'false'] }); function main(conf) { @@ -31,22 +32,34 @@ function main(conf) { } if (conf.fullPath === 'true') - measureFull(n); + measureFull(n, conf.useCache === 'true'); else - measureDir(n); + measureDir(n, conf.useCache === 'true'); } -function measureFull(n) { +function measureFull(n, useCache) { + var i; + if (useCache) { + for (i = 0; i <= n; i++) { + require(benchmarkDirectory + i + '/index.js'); + } + } bench.start(); - for (var i = 0; i <= n; i++) { + for (i = 0; i <= n; i++) { require(benchmarkDirectory + i + '/index.js'); } bench.end(n / 1e3); } -function measureDir(n) { +function measureDir(n, useCache) { + var i; + if (useCache) { + for (i = 0; i <= n; i++) { + require(benchmarkDirectory + i); + } + } bench.start(); - for (var i = 0; i <= n; i++) { + for (i = 0; i <= n; i++) { require(benchmarkDirectory + i); } bench.end(n / 1e3); From 21b24401768aa111142522fd56a49f8de805fd74 Mon Sep 17 00:00:00 2001 From: Brian White Date: Fri, 13 Jan 2017 05:04:18 -0500 Subject: [PATCH 02/10] fs: avoid recompilation of closure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: /~https://github.com/nodejs/node/pull/10789 Reviewed-By: James M Snell Reviewed-By: Michaël Zasso Reviewed-By: Michael Dawson Reviewed-By: Matteo Collina Reviewed-By: Benjamin Gruenbaum --- lib/fs.js | 86 +++++++++++++++++++++++++++++++++---------------------- 1 file changed, 51 insertions(+), 35 deletions(-) diff --git a/lib/fs.js b/lib/fs.js index 929f7bcaa6b30b..eab8d942e183f0 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -1527,21 +1527,16 @@ fs.realpathSync = function realpathSync(p, options) { // the partial path scanned in the previous round, with slash var previous; - start(); + // Skip over roots + var m = splitRootRe.exec(p); + pos = m[0].length; + current = m[0]; + base = m[0]; - function start() { - // Skip over roots - var m = splitRootRe.exec(p); - pos = m[0].length; - current = m[0]; - base = m[0]; - previous = ''; - - // On windows, check that the root exists. On unix there is no need. - if (isWindows && !knownHard[base]) { - fs.lstatSync(base); - knownHard[base] = true; - } + // On windows, check that the root exists. On unix there is no need. + if (isWindows && !knownHard[base]) { + fs.lstatSync(base); + knownHard[base] = true; } // walk down the path, swapping out linked pathparts for their real @@ -1595,7 +1590,18 @@ fs.realpathSync = function realpathSync(p, options) { // resolve the link, then start over p = pathModule.resolve(resolvedLink, p.slice(pos)); - start(); + + // Skip over roots + m = splitRootRe.exec(p); + pos = m[0].length; + current = m[0]; + base = m[0]; + + // On windows, check that the root exists. On unix there is no need. + if (isWindows && !knownHard[base]) { + fs.lstatSync(base); + knownHard[base] = true; + } } if (cache) cache.set(original, p); @@ -1626,26 +1632,21 @@ fs.realpath = function realpath(p, options, callback) { // the partial path scanned in the previous round, with slash var previous; - start(); - - function start() { - // Skip over roots - var m = splitRootRe.exec(p); - pos = m[0].length; - current = m[0]; - base = m[0]; - previous = ''; + var m = splitRootRe.exec(p); + pos = m[0].length; + current = m[0]; + base = m[0]; + previous = ''; - // On windows, check that the root exists. On unix there is no need. - if (isWindows && !knownHard[base]) { - fs.lstat(base, function(err) { - if (err) return callback(err); - knownHard[base] = true; - LOOP(); - }); - } else { - process.nextTick(LOOP); - } + // On windows, check that the root exists. On unix there is no need. + if (isWindows && !knownHard[base]) { + fs.lstat(base, function(err) { + if (err) return callback(err); + knownHard[base] = true; + LOOP(); + }); + } else { + process.nextTick(LOOP); } // walk down the path, swapping out linked pathparts for their real @@ -1711,7 +1712,22 @@ fs.realpath = function realpath(p, options, callback) { function gotResolvedLink(resolvedLink) { // resolve the link, then start over p = pathModule.resolve(resolvedLink, p.slice(pos)); - start(); + var m = splitRootRe.exec(p); + pos = m[0].length; + current = m[0]; + base = m[0]; + previous = ''; + + // On windows, check that the root exists. On unix there is no need. + if (isWindows && !knownHard[base]) { + fs.lstat(base, function(err) { + if (err) return callback(err); + knownHard[base] = true; + LOOP(); + }); + } else { + process.nextTick(LOOP); + } } }; From 34c9fc2e4e12fa9aa58d94a3283193444302a3ab Mon Sep 17 00:00:00 2001 From: Brian White Date: Fri, 13 Jan 2017 05:07:18 -0500 Subject: [PATCH 03/10] fs: avoid multiple conversions to string MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit nullCheck() implicitly converts the argument to string when checking the value, so this commit avoids any unnecessary additional (Buffer) conversions to string. PR-URL: /~https://github.com/nodejs/node/pull/10789 Reviewed-By: James M Snell Reviewed-By: Michaël Zasso Reviewed-By: Michael Dawson Reviewed-By: Matteo Collina Reviewed-By: Benjamin Gruenbaum --- lib/fs.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/fs.js b/lib/fs.js index eab8d942e183f0..3e9a0540dd9d12 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -1503,21 +1503,21 @@ function encodeRealpathResult(result, options) { fs.realpathSync = function realpathSync(p, options) { options = getOptions(options, {}); handleError((p = getPathFromURL(p))); + if (typeof p !== 'string') + p += ''; nullCheck(p); - - p = p.toString('utf8'); p = pathModule.resolve(p); - const seenLinks = {}; - const knownHard = {}; const cache = options[internalFS.realpathCacheKey]; - const original = p; - const maybeCachedResult = cache && cache.get(p); if (maybeCachedResult) { return maybeCachedResult; } + const seenLinks = {}; + const knownHard = {}; + const original = p; + // current character position in p var pos; // the partial path so far, including a trailing slash if any @@ -1614,10 +1614,10 @@ fs.realpath = function realpath(p, options, callback) { options = getOptions(options, {}); if (handleError((p = getPathFromURL(p)), callback)) return; + if (typeof p !== 'string') + p += ''; if (!nullCheck(p, callback)) return; - - p = p.toString('utf8'); p = pathModule.resolve(p); const seenLinks = {}; From 1c3df965705d156db7b8132b86b3193a7467a2e2 Mon Sep 17 00:00:00 2001 From: Brian White Date: Fri, 13 Jan 2017 05:09:52 -0500 Subject: [PATCH 04/10] fs: replace regexp with function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replacing the path separator-finding regexp with a custom function results in a measurable improvement in performance. PR-URL: /~https://github.com/nodejs/node/pull/10789 Reviewed-By: James M Snell Reviewed-By: Michaël Zasso Reviewed-By: Michael Dawson Reviewed-By: Matteo Collina Reviewed-By: Benjamin Gruenbaum --- lib/fs.js | 53 +++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 37 insertions(+), 16 deletions(-) diff --git a/lib/fs.js b/lib/fs.js index 3e9a0540dd9d12..7cf96d88f18d98 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -1478,12 +1478,6 @@ fs.unwatchFile = function(filename, listener) { }; -// Regexp that finds the next portion of a (partial) path -// result is [base_with_slash, base], e.g. ['somedir/', 'somedir'] -const nextPartRe = isWindows ? - /(.*?)(?:[/\\]+|$)/g : - /(.*?)(?:[/]+|$)/g; - // Regex to find the device root, including trailing slash. E.g. 'c:\\'. const splitRootRe = isWindows ? /^(?:[a-zA-Z]:|[\\/]{2}[^\\/]+[\\/][^\\/]+)?[\\/]*/ : @@ -1500,6 +1494,21 @@ function encodeRealpathResult(result, options) { } } +// Finds the next portion of a (partial) path, up to the next path delimiter +var nextPart; +if (isWindows) { + nextPart = function nextPart(p, i) { + for (; i < p.length; ++i) { + const ch = p.charCodeAt(i); + if (ch === 92/*'\'*/ || ch === 47/*'/'*/) + return i; + } + return -1; + }; +} else { + nextPart = function nextPart(p, i) { return p.indexOf('/', i); }; +} + fs.realpathSync = function realpathSync(p, options) { options = getOptions(options, {}); handleError((p = getPathFromURL(p))); @@ -1544,12 +1553,18 @@ fs.realpathSync = function realpathSync(p, options) { // NB: p.length changes. while (pos < p.length) { // find the next part - nextPartRe.lastIndex = pos; - var result = nextPartRe.exec(p); + var result = nextPart(p, pos); previous = current; - current += result[0]; - base = previous + result[1]; - pos = nextPartRe.lastIndex; + if (result === -1) { + var last = p.slice(pos); + current += last; + base = previous + last; + pos = p.length; + } else { + current += p.slice(pos, result + 1); + base = previous + p.slice(pos, result); + pos = result + 1; + } // continue if not a symlink if (knownHard[base] || (cache && cache.get(base) === base)) { @@ -1658,12 +1673,18 @@ fs.realpath = function realpath(p, options, callback) { } // find the next part - nextPartRe.lastIndex = pos; - var result = nextPartRe.exec(p); + var result = nextPart(p, pos); previous = current; - current += result[0]; - base = previous + result[1]; - pos = nextPartRe.lastIndex; + if (result === -1) { + var last = p.slice(pos); + current += last; + base = previous + last; + pos = p.length; + } else { + current += p.slice(pos, result + 1); + base = previous + p.slice(pos, result); + pos = result + 1; + } // continue if not a symlink if (knownHard[base]) { From a851b868c0a475c29e5af4c0414f9b2d1fa8d26f Mon Sep 17 00:00:00 2001 From: Brian White Date: Fri, 13 Jan 2017 05:11:11 -0500 Subject: [PATCH 05/10] lib: remove sources of permanent deopts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: /~https://github.com/nodejs/node/pull/10789 Reviewed-By: James M Snell Reviewed-By: Michaël Zasso Reviewed-By: Michael Dawson Reviewed-By: Matteo Collina Reviewed-By: Benjamin Gruenbaum --- lib/fs.js | 6 +++--- lib/module.js | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/fs.js b/lib/fs.js index 7cf96d88f18d98..d8ae0b09ba414e 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -1572,7 +1572,7 @@ fs.realpathSync = function realpathSync(p, options) { } var resolvedLink; - const maybeCachedResolved = cache && cache.get(base); + var maybeCachedResolved = cache && cache.get(base); if (maybeCachedResolved) { resolvedLink = maybeCachedResolved; } else { @@ -1585,8 +1585,8 @@ fs.realpathSync = function realpathSync(p, options) { // read the link if it wasn't read before // dev/ino always return 0 on windows, so skip the check. - let linkTarget = null; - let id; + var linkTarget = null; + var id; if (!isWindows) { id = `${stat.dev.toString(32)}:${stat.ino.toString(32)}`; if (seenLinks.hasOwnProperty(id)) { diff --git a/lib/module.js b/lib/module.js index 2b1450aa26550e..f40a9aebb1592e 100644 --- a/lib/module.js +++ b/lib/module.js @@ -179,8 +179,8 @@ Module._findPath = function(request, paths, isMain) { } var exts; - const trailingSlash = request.length > 0 && - request.charCodeAt(request.length - 1) === 47/*/*/; + var trailingSlash = request.length > 0 && + request.charCodeAt(request.length - 1) === 47/*/*/; // For each path for (var i = 0; i < paths.length; i++) { @@ -190,7 +190,7 @@ Module._findPath = function(request, paths, isMain) { var basePath = path.resolve(curPath, request); var filename; - const rc = stat(basePath); + var rc = stat(basePath); if (!trailingSlash) { if (rc === 0) { // File. if (preserveSymlinks && !isMain) { From 298a40e04ee496dbd6b2324a20d9ff745fef74cb Mon Sep 17 00:00:00 2001 From: Brian White Date: Fri, 13 Jan 2017 05:12:54 -0500 Subject: [PATCH 06/10] module: use "clean" objects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: /~https://github.com/nodejs/node/pull/10789 Reviewed-By: James M Snell Reviewed-By: Michaël Zasso Reviewed-By: Michael Dawson Reviewed-By: Matteo Collina Reviewed-By: Benjamin Gruenbaum --- lib/module.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/module.js b/lib/module.js index f40a9aebb1592e..bd6af190f642b1 100644 --- a/lib/module.js +++ b/lib/module.js @@ -69,9 +69,9 @@ function Module(id, parent) { } module.exports = Module; -Module._cache = {}; -Module._pathCache = {}; -Module._extensions = {}; +Module._cache = Object.create(null); +Module._pathCache = Object.create(null); +Module._extensions = Object.create(null); var modulePaths = []; Module.globalPaths = []; From 403b89e72b6367934ca3c36d389ce0f3214ffbf5 Mon Sep 17 00:00:00 2001 From: Brian White Date: Fri, 13 Jan 2017 05:13:53 -0500 Subject: [PATCH 07/10] module: avoid hasOwnProperty() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit hasOwnProperty() is known to be slow, do a direct lookup on a "clean" object instead. PR-URL: /~https://github.com/nodejs/node/pull/10789 Reviewed-By: James M Snell Reviewed-By: Michaël Zasso Reviewed-By: Michael Dawson Reviewed-By: Matteo Collina Reviewed-By: Benjamin Gruenbaum --- lib/module.js | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/lib/module.js b/lib/module.js index bd6af190f642b1..8916b3b36c2e6f 100644 --- a/lib/module.js +++ b/lib/module.js @@ -33,14 +33,6 @@ const internalModuleReadFile = process.binding('fs').internalModuleReadFile; const internalModuleStat = process.binding('fs').internalModuleStat; const preserveSymlinks = !!process.binding('config').preserveSymlinks; -// If obj.hasOwnProperty has been overridden, then calling -// obj.hasOwnProperty(prop) will break. -// See: /~https://github.com/joyent/node/issues/1707 -function hasOwnProperty(obj, prop) { - return Object.prototype.hasOwnProperty.call(obj, prop); -} - - function stat(filename) { filename = path._makeLong(filename); const cache = stat.cache; @@ -95,12 +87,12 @@ const debug = Module._debug; // -> a/index. // check if the directory is a package.json dir -const packageMainCache = {}; +const packageMainCache = Object.create(null); function readPackage(requestPath) { - if (hasOwnProperty(packageMainCache, requestPath)) { - return packageMainCache[requestPath]; - } + const entry = packageMainCache[requestPath]; + if (entry) + return entry; const jsonPath = path.resolve(requestPath, 'package.json'); const json = internalModuleReadFile(path._makeLong(jsonPath)); From 28dc848e702b70f8c07941a1dfd46227f90c8267 Mon Sep 17 00:00:00 2001 From: Brian White Date: Fri, 13 Jan 2017 05:16:46 -0500 Subject: [PATCH 08/10] lib: improve method of function calling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Using a more "direct" method of function calling yields better performance. PR-URL: /~https://github.com/nodejs/node/pull/10789 Reviewed-By: James M Snell Reviewed-By: Michaël Zasso Reviewed-By: Michael Dawson Reviewed-By: Matteo Collina Reviewed-By: Benjamin Gruenbaum --- lib/internal/module.js | 13 ++++++------- lib/module.js | 6 +++--- lib/repl.js | 2 +- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/lib/internal/module.js b/lib/internal/module.js index 2f38618daac5f7..8fc8dfbf327e61 100644 --- a/lib/internal/module.js +++ b/lib/internal/module.js @@ -8,23 +8,22 @@ exports = module.exports = { exports.requireDepth = 0; -// Invoke with makeRequireFunction.call(module) where |module| is the -// Module object to use as the context for the require() function. -function makeRequireFunction() { - const Module = this.constructor; - const self = this; +// Invoke with makeRequireFunction(module) where |module| is the Module object +// to use as the context for the require() function. +function makeRequireFunction(mod) { + const Module = mod.constructor; function require(path) { try { exports.requireDepth += 1; - return self.require(path); + return mod.require(path); } finally { exports.requireDepth -= 1; } } function resolve(request) { - return Module._resolveFilename(request, self); + return Module._resolveFilename(request, mod); } require.resolve = resolve; diff --git a/lib/module.js b/lib/module.js index 8916b3b36c2e6f..1b9c2413b7ce9e 100644 --- a/lib/module.js +++ b/lib/module.js @@ -577,11 +577,11 @@ Module.prototype._compile = function(content, filename) { } } var dirname = path.dirname(filename); - var require = internalModule.makeRequireFunction.call(this); - var args = [this.exports, require, this, filename, dirname]; + var require = internalModule.makeRequireFunction(this); var depth = internalModule.requireDepth; if (depth === 0) stat.cache = new Map(); - var result = compiledWrapper.apply(this.exports, args); + var result = compiledWrapper.call(this.exports, this.exports, require, this, + filename, dirname); if (depth === 0) stat.cache = null; return result; }; diff --git a/lib/repl.js b/lib/repl.js index 3dd243b0b0cdbf..676fa105861d33 100644 --- a/lib/repl.js +++ b/lib/repl.js @@ -714,7 +714,7 @@ REPLServer.prototype.createContext = function() { const module = new Module(''); module.paths = Module._resolveLookupPaths('', parentModule)[1]; - const require = internalModule.makeRequireFunction.call(module); + const require = internalModule.makeRequireFunction(module); context.module = module; context.require = require; From e32425bfcd55497cdad4982908d6fcba9a0e033c Mon Sep 17 00:00:00 2001 From: Brian White Date: Fri, 13 Jan 2017 05:19:54 -0500 Subject: [PATCH 09/10] module: avoid JSON.stringify() for cache key MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit By avoiding JSON.stringify() and simply joining the strings with a delimiter that does not appear in paths, we can improve cached require() performance by at least 50%. Additionally, this commit removes the last source of permanent function deoptimization (const) for _findPath(). PR-URL: /~https://github.com/nodejs/node/pull/10789 Reviewed-By: James M Snell Reviewed-By: Michaël Zasso Reviewed-By: Michael Dawson Reviewed-By: Matteo Collina Reviewed-By: Benjamin Gruenbaum --- lib/module.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/module.js b/lib/module.js index 1b9c2413b7ce9e..77675fcd980421 100644 --- a/lib/module.js +++ b/lib/module.js @@ -165,10 +165,11 @@ Module._findPath = function(request, paths, isMain) { return false; } - const cacheKey = JSON.stringify({request: request, paths: paths}); - if (Module._pathCache[cacheKey]) { - return Module._pathCache[cacheKey]; - } + var cacheKey = request + '\x00' + + (paths.length === 1 ? paths[0] : paths.join('\x00')); + var entry = Module._pathCache[cacheKey]; + if (entry) + return entry; var exts; var trailingSlash = request.length > 0 && From c67207731f16a78f6cae90e49c53b10728241ecf Mon Sep 17 00:00:00 2001 From: Brian White Date: Fri, 13 Jan 2017 05:22:27 -0500 Subject: [PATCH 10/10] lib: simplify Module._resolveLookupPaths MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit consists of two changes: * Avoids returning request/id *just* for the debug() output * Returns `null` instead of an empty array for the list of paths PR-URL: /~https://github.com/nodejs/node/pull/10789 Reviewed-By: James M Snell Reviewed-By: Michaël Zasso Reviewed-By: Michael Dawson Reviewed-By: Matteo Collina Reviewed-By: Benjamin Gruenbaum --- lib/module.js | 29 ++++++++++---------- lib/repl.js | 2 +- test/parallel/test-module-relative-lookup.js | 7 ++++- 3 files changed, 22 insertions(+), 16 deletions(-) diff --git a/lib/module.js b/lib/module.js index 77675fcd980421..115afc7553ad82 100644 --- a/lib/module.js +++ b/lib/module.js @@ -326,14 +326,14 @@ if (process.platform === 'win32') { // 'index.' character codes var indexChars = [ 105, 110, 100, 101, 120, 46 ]; var indexLen = indexChars.length; -Module._resolveLookupPaths = function(request, parent) { +Module._resolveLookupPaths = function(request, parent, newReturn) { if (NativeModule.nonInternalExists(request)) { - return [request, []]; + debug('looking for %j in []', request); + return (newReturn ? null : [request, []]); } - var reqLen = request.length; // Check for relative path - if (reqLen < 2 || + if (request.length < 2 || request.charCodeAt(0) !== 46/*.*/ || (request.charCodeAt(1) !== 46/*.*/ && request.charCodeAt(1) !== 47/*/*/)) { @@ -355,7 +355,8 @@ Module._resolveLookupPaths = function(request, parent) { } } - return [request, paths]; + debug('looking for %j in %j', request, paths); + return (newReturn ? (paths.length > 0 ? paths : null) : [request, paths]); } // with --eval, parent.id is not set and parent.filename is null @@ -363,7 +364,9 @@ Module._resolveLookupPaths = function(request, parent) { // make require('./path/to/foo') work - normally the path is taken // from realpath(__filename) but with eval there is no filename var mainPaths = ['.'].concat(Module._nodeModulePaths('.'), modulePaths); - return [request, mainPaths]; + + debug('looking for %j in %j', request, mainPaths); + return (newReturn ? mainPaths : [request, mainPaths]); } // Is the parent an index module? @@ -413,7 +416,9 @@ Module._resolveLookupPaths = function(request, parent) { debug('RELATIVE: requested: %s set ID to: %s from %s', request, id, parent.id); - return [id, [path.dirname(parent.filename)]]; + var parentDir = [path.dirname(parent.filename)]; + debug('looking for %j in %j', id, parentDir); + return (newReturn ? parentDir : [id, parentDir]); }; @@ -472,16 +477,12 @@ Module._resolveFilename = function(request, parent, isMain) { return request; } - var resolvedModule = Module._resolveLookupPaths(request, parent); - var id = resolvedModule[0]; - var paths = resolvedModule[1]; + var paths = Module._resolveLookupPaths(request, parent, true); // look up the filename first, since that's the cache key. - debug('looking for %j in %j', id, paths); - var filename = Module._findPath(request, paths, isMain); if (!filename) { - var err = new Error("Cannot find module '" + request + "'"); + var err = new Error(`Cannot find module '${request}'`); err.code = 'MODULE_NOT_FOUND'; throw err; } @@ -564,7 +565,7 @@ Module.prototype._compile = function(content, filename) { if (!resolvedArgv) { // we enter the repl if we're not given a filename argument. if (process.argv[1]) { - resolvedArgv = Module._resolveFilename(process.argv[1], null); + resolvedArgv = Module._resolveFilename(process.argv[1], null, false); } else { resolvedArgv = 'repl'; } diff --git a/lib/repl.js b/lib/repl.js index 676fa105861d33..b00666267a646b 100644 --- a/lib/repl.js +++ b/lib/repl.js @@ -712,7 +712,7 @@ REPLServer.prototype.createContext = function() { } const module = new Module(''); - module.paths = Module._resolveLookupPaths('', parentModule)[1]; + module.paths = Module._resolveLookupPaths('', parentModule, true) || []; const require = internalModule.makeRequireFunction(module); context.module = module; diff --git a/test/parallel/test-module-relative-lookup.js b/test/parallel/test-module-relative-lookup.js index 2ecb412ce22782..6ebb8ee1881962 100644 --- a/test/parallel/test-module-relative-lookup.js +++ b/test/parallel/test-module-relative-lookup.js @@ -4,7 +4,12 @@ require('../common'); const assert = require('assert'); const _module = require('module'); // avoid collision with global.module const lookupResults = _module._resolveLookupPaths('./lodash'); -const paths = lookupResults[1]; +let paths = lookupResults[1]; assert.strictEqual(paths[0], '.', 'Current directory gets highest priority for local modules'); + +paths = _module._resolveLookupPaths('./lodash', null, true); + +assert.strictEqual(paths && paths[0], '.', + 'Current directory gets highest priority for local modules');