Skip to content

Commit 9cf2e1f

Browse files
H4adjuanarbol
authored andcommitted
src,lib: reducing C++ calls of esm legacy main resolve
Instead of many C++ calls, now we make only one C++ call to return a enum number that represents the selected state. PR-URL: #48325 Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com> Reviewed-By: Geoffrey Booth <webadmin@geoffreybooth.com> Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com>
1 parent 332e480 commit 9cf2e1f

File tree

10 files changed

+715
-45
lines changed

10 files changed

+715
-45
lines changed
+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// Tests the impact on eager operations required for policies affecting
2+
// general startup, does not test lazy operations
3+
'use strict';
4+
const fs = require('node:fs');
5+
const path = require('node:path');
6+
const common = require('../common.js');
7+
8+
const tmpdir = require('../../test/common/tmpdir.js');
9+
const { pathToFileURL } = require('node:url');
10+
11+
const benchmarkDirectory =
12+
path.resolve(tmpdir.path, 'benchmark-import-meta-resolve');
13+
14+
const configs = {
15+
n: [1e4],
16+
packageJsonUrl: [
17+
'node_modules/test/package.json',
18+
],
19+
packageConfigMain: ['', './index.js'],
20+
resolvedFile: [
21+
'node_modules/test/index.js',
22+
'node_modules/test/index.json',
23+
'node_modules/test/index.node',
24+
'node_modules/non-exist',
25+
],
26+
};
27+
28+
const options = {
29+
flags: ['--expose-internals'],
30+
};
31+
32+
const bench = common.createBenchmark(main, configs, options);
33+
34+
function main(conf) {
35+
const { legacyMainResolve } = require('internal/modules/esm/resolve');
36+
tmpdir.refresh();
37+
38+
fs.mkdirSync(path.join(benchmarkDirectory, 'node_modules', 'test'), { recursive: true });
39+
fs.writeFileSync(path.join(benchmarkDirectory, conf.resolvedFile), '\n');
40+
41+
const packageJsonUrl = pathToFileURL(conf.packageJsonUrl);
42+
const packageConfigMain = { main: conf.packageConfigMain };
43+
44+
bench.start();
45+
46+
for (let i = 0; i < conf.n; i++) {
47+
try {
48+
legacyMainResolve(packageJsonUrl, packageConfigMain, undefined);
49+
} catch { /* empty */ }
50+
}
51+
52+
bench.end(conf.n);
53+
}

lib/internal/modules/esm/resolve.js

+46-45
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,9 @@ const preserveSymlinksMain = getOptionValue('--preserve-symlinks-main');
3636
const experimentalNetworkImports =
3737
getOptionValue('--experimental-network-imports');
3838
const typeFlag = getOptionValue('--input-type');
39-
const { URL, pathToFileURL, fileURLToPath, isURL, toPathIfFileURL } = require('internal/url');
39+
const { URL, pathToFileURL, fileURLToPath, isURL } = require('internal/url');
4040
const { canParse: URLCanParse } = internalBinding('url');
41+
const { legacyMainResolve: FSLegacyMainResolve } = internalBinding('fs');
4142
const {
4243
ERR_INPUT_TYPE_NOT_ALLOWED,
4344
ERR_INVALID_ARG_TYPE,
@@ -133,13 +134,34 @@ function emitLegacyIndexDeprecation(url, packageJSONUrl, base, main) {
133134

134135
const realpathCache = new SafeMap();
135136

136-
/**
137-
* @param {string | URL} url
138-
* @returns {boolean}
139-
*/
140-
function fileExists(url) {
141-
return internalModuleStat(toNamespacedPath(toPathIfFileURL(url))) === 0;
142-
}
137+
const legacyMainResolveExtensions = [
138+
'',
139+
'.js',
140+
'.json',
141+
'.node',
142+
'/index.js',
143+
'/index.json',
144+
'/index.node',
145+
'./index.js',
146+
'./index.json',
147+
'./index.node',
148+
];
149+
150+
const legacyMainResolveExtensionsIndexes = {
151+
// 0-6: when packageConfig.main is defined
152+
kResolvedByMain: 0,
153+
kResolvedByMainJs: 1,
154+
kResolvedByMainJson: 2,
155+
kResolvedByMainNode: 3,
156+
kResolvedByMainIndexJs: 4,
157+
kResolvedByMainIndexJson: 5,
158+
kResolvedByMainIndexNode: 6,
159+
// 7-9: when packageConfig.main is NOT defined,
160+
// or when the previous case didn't found the file
161+
kResolvedByPackageAndJs: 7,
162+
kResolvedByPackageAndJson: 8,
163+
kResolvedByPackageAndNode: 9,
164+
};
143165

144166
/**
145167
* Legacy CommonJS main resolution:
@@ -154,44 +176,22 @@ function fileExists(url) {
154176
* @returns {URL}
155177
*/
156178
function legacyMainResolve(packageJSONUrl, packageConfig, base) {
157-
let guess;
158-
if (packageConfig.main !== undefined) {
159-
// Note: fs check redundances will be handled by Descriptor cache here.
160-
if (fileExists(guess = new URL(`./${packageConfig.main}`,
161-
packageJSONUrl))) {
162-
return guess;
163-
} else if (fileExists(guess = new URL(`./${packageConfig.main}.js`,
164-
packageJSONUrl)));
165-
else if (fileExists(guess = new URL(`./${packageConfig.main}.json`,
166-
packageJSONUrl)));
167-
else if (fileExists(guess = new URL(`./${packageConfig.main}.node`,
168-
packageJSONUrl)));
169-
else if (fileExists(guess = new URL(`./${packageConfig.main}/index.js`,
170-
packageJSONUrl)));
171-
else if (fileExists(guess = new URL(`./${packageConfig.main}/index.json`,
172-
packageJSONUrl)));
173-
else if (fileExists(guess = new URL(`./${packageConfig.main}/index.node`,
174-
packageJSONUrl)));
175-
else guess = undefined;
176-
if (guess) {
177-
emitLegacyIndexDeprecation(guess, packageJSONUrl, base,
178-
packageConfig.main);
179-
return guess;
180-
}
181-
// Fallthrough.
182-
}
183-
if (fileExists(guess = new URL('./index.js', packageJSONUrl)));
184-
// So fs.
185-
else if (fileExists(guess = new URL('./index.json', packageJSONUrl)));
186-
else if (fileExists(guess = new URL('./index.node', packageJSONUrl)));
187-
else guess = undefined;
188-
if (guess) {
189-
emitLegacyIndexDeprecation(guess, packageJSONUrl, base, packageConfig.main);
190-
return guess;
179+
const packageJsonUrlString = packageJSONUrl.href;
180+
181+
if (typeof packageJsonUrlString !== 'string') {
182+
throw new ERR_INVALID_ARG_TYPE('packageJSONUrl', ['URL'], packageJSONUrl);
191183
}
192-
// Not found.
193-
throw new ERR_MODULE_NOT_FOUND(
194-
fileURLToPath(new URL('.', packageJSONUrl)), fileURLToPath(base));
184+
185+
const baseStringified = isURL(base) ? base.href : base;
186+
187+
const resolvedOption = FSLegacyMainResolve(packageJsonUrlString, packageConfig.main, baseStringified);
188+
189+
const baseUrl = resolvedOption <= legacyMainResolveExtensionsIndexes.kResolvedByMainIndexNode ? `./${packageConfig.main}` : '';
190+
const resolvedUrl = new URL(baseUrl + legacyMainResolveExtensions[resolvedOption], packageJSONUrl);
191+
192+
emitLegacyIndexDeprecation(resolvedUrl, packageJSONUrl, base, packageConfig.main);
193+
194+
return resolvedUrl;
195195
}
196196

197197
const encodedSepRegEx = /%2F|%5C/i;
@@ -1078,6 +1078,7 @@ module.exports = {
10781078
packageExportsResolve,
10791079
packageImportsResolve,
10801080
throwIfInvalidParentURL,
1081+
legacyMainResolve,
10811082
};
10821083

10831084
// cycle

src/node_errors.h

+5
Original file line numberDiff line numberDiff line change
@@ -69,18 +69,22 @@ void AppendExceptionLine(Environment* env,
6969
V(ERR_INVALID_ARG_VALUE, TypeError) \
7070
V(ERR_OSSL_EVP_INVALID_DIGEST, Error) \
7171
V(ERR_INVALID_ARG_TYPE, TypeError) \
72+
V(ERR_INVALID_FILE_URL_HOST, TypeError) \
73+
V(ERR_INVALID_FILE_URL_PATH, TypeError) \
7274
V(ERR_INVALID_OBJECT_DEFINE_PROPERTY, TypeError) \
7375
V(ERR_INVALID_MODULE, Error) \
7476
V(ERR_INVALID_STATE, Error) \
7577
V(ERR_INVALID_THIS, TypeError) \
7678
V(ERR_INVALID_TRANSFER_OBJECT, TypeError) \
7779
V(ERR_INVALID_URL, TypeError) \
80+
V(ERR_INVALID_URL_SCHEME, TypeError) \
7881
V(ERR_MEMORY_ALLOCATION_FAILED, Error) \
7982
V(ERR_MESSAGE_TARGET_CONTEXT_UNAVAILABLE, Error) \
8083
V(ERR_MISSING_ARGS, TypeError) \
8184
V(ERR_MISSING_TRANSFERABLE_IN_TRANSFER_LIST, TypeError) \
8285
V(ERR_MISSING_PASSPHRASE, TypeError) \
8386
V(ERR_MISSING_PLATFORM_FOR_WORKER, Error) \
87+
V(ERR_MODULE_NOT_FOUND, Error) \
8488
V(ERR_NON_CONTEXT_AWARE_DISABLED, Error) \
8589
V(ERR_OUT_OF_RANGE, RangeError) \
8690
V(ERR_SCRIPT_EXECUTION_INTERRUPTED, Error) \
@@ -165,6 +169,7 @@ ERRORS_WITH_CODE(V)
165169
V(ERR_INVALID_STATE, "Invalid state") \
166170
V(ERR_INVALID_THIS, "Value of \"this\" is the wrong type") \
167171
V(ERR_INVALID_TRANSFER_OBJECT, "Found invalid object in transferList") \
172+
V(ERR_INVALID_URL_SCHEME, "The URL must be of scheme file:") \
168173
V(ERR_MEMORY_ALLOCATION_FAILED, "Failed to allocate memory") \
169174
V(ERR_OSSL_EVP_INVALID_DIGEST, "Invalid digest used") \
170175
V(ERR_MESSAGE_TARGET_CONTEXT_UNAVAILABLE, \

0 commit comments

Comments
 (0)