From 3e600bf2c77f838287e91d9f9d3ba66adaa466cf Mon Sep 17 00:00:00 2001 From: Yagiz Nizipli Date: Sun, 23 Apr 2023 19:52:26 -0400 Subject: [PATCH] lib: improve esm resolve performance MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/nodejs/node/pull/46652 Refs: https://github.com/nodejs/performance/issues/39 Reviewed-By: Antoine du Hamel Reviewed-By: Michaƫl Zasso Reviewed-By: Matteo Collina Reviewed-By: Rafael Gonzaga Reviewed-By: James M Snell Reviewed-By: Erick Wendel Reviewed-By: Geoffrey Booth Reviewed-By: Benjamin Gruenbaum --- lib/internal/modules/esm/resolve.js | 38 ++++++++++++----------------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/lib/internal/modules/esm/resolve.js b/lib/internal/modules/esm/resolve.js index 43cfdb61e8aa95..e77effbf9b017d 100644 --- a/lib/internal/modules/esm/resolve.js +++ b/lib/internal/modules/esm/resolve.js @@ -25,23 +25,19 @@ const { } = primordials; const internalFS = require('internal/fs/utils'); const { BuiltinModule } = require('internal/bootstrap/realm'); -const { - realpathSync, - statSync, - Stats, -} = require('fs'); +const { realpathSync } = require('fs'); const { getOptionValue } = require('internal/options'); // Do not eagerly grab .manifest, it may be in TDZ const policy = getOptionValue('--experimental-policy') ? require('internal/process/policy') : null; -const { sep, relative } = require('path'); +const { sep, relative, toNamespacedPath } = require('path'); const preserveSymlinks = getOptionValue('--preserve-symlinks'); const preserveSymlinksMain = getOptionValue('--preserve-symlinks-main'); const experimentalNetworkImports = getOptionValue('--experimental-network-imports'); const typeFlag = getOptionValue('--input-type'); -const { URL, pathToFileURL, fileURLToPath, isURL } = require('internal/url'); +const { URL, pathToFileURL, fileURLToPath, isURL, toPathIfFileURL } = require('internal/url'); const { canParse: canParseURL } = internalBinding('url'); const { ERR_INPUT_TYPE_NOT_ALLOWED, @@ -61,6 +57,7 @@ const { const { Module: CJSModule } = require('internal/modules/cjs/loader'); const { getPackageConfig, getPackageScopeConfig } = require('internal/modules/esm/package_config'); const { getConditionsSet } = require('internal/modules/esm/utils'); +const { internalModuleStat } = internalBinding('fs'); /** * @typedef {import('internal/modules/esm/package_config.js').PackageConfig} PackageConfig @@ -137,19 +134,12 @@ function emitLegacyIndexDeprecation(url, packageJSONUrl, base, main) { const realpathCache = new SafeMap(); -/** - * @param {string | URL} path - * @returns {import('fs').Stats} - */ -const tryStatSync = - (path) => statSync(path, { throwIfNoEntry: false }) ?? new Stats(); - /** * @param {string | URL} url * @returns {boolean} */ function fileExists(url) { - return statSync(url, { throwIfNoEntry: false })?.isFile() ?? false; + return internalModuleStat(toNamespacedPath(toPathIfFileURL(url))) === 0; } /** @@ -220,13 +210,16 @@ function finalizeResolution(resolved, base, preserveSymlinks) { const path = fileURLToPath(resolved); - const stats = tryStatSync(StringPrototypeEndsWith(path, '/') ? - StringPrototypeSlice(path, -1) : path); - if (stats.isDirectory()) { + const stats = internalModuleStat(toNamespacedPath(StringPrototypeEndsWith(path, '/') ? + StringPrototypeSlice(path, -1) : path)); + + // Check for stats.isDirectory() + if (stats === 1) { const err = new ERR_UNSUPPORTED_DIR_IMPORT(path, fileURLToPath(base)); err.url = String(resolved); throw err; - } else if (!stats.isFile()) { + } else if (stats !== 0) { + // Check for !stats.isFile() if (process.env.WATCH_REPORT_DEPENDENCIES && process.send) { process.send({ 'watch:require': [path || resolved.pathname] }); } @@ -755,9 +748,10 @@ function packageResolve(specifier, base, conditions) { let packageJSONPath = fileURLToPath(packageJSONUrl); let lastPath; do { - const stat = tryStatSync(StringPrototypeSlice(packageJSONPath, 0, - packageJSONPath.length - 13)); - if (!stat.isDirectory()) { + const stat = internalModuleStat(toNamespacedPath(StringPrototypeSlice(packageJSONPath, 0, + packageJSONPath.length - 13))); + // Check for !stat.isDirectory() + if (stat !== 1) { lastPath = packageJSONPath; packageJSONUrl = new URL((isScoped ? '../../../../node_modules/' : '../../../node_modules/') +