Skip to content

Commit 8d5469c

Browse files
fasttimeUlisesGascon
authored andcommitted
esm: do not call getSource when format is commonjs
Ensure that `defaultLoad` does not uselessly access the file system to get the source of modules that are known to be in CommonJS format. This allows CommonJS imports to resolve in the current phase of the event loop. Refs: eslint/eslint#17683 PR-URL: #50465 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
1 parent 1862235 commit 8d5469c

File tree

6 files changed

+69
-9
lines changed

6 files changed

+69
-9
lines changed

lib/internal/modules/esm/load.js

+10-9
Original file line numberDiff line numberDiff line change
@@ -132,20 +132,21 @@ async function defaultLoad(url, context = kEmptyObject) {
132132
if (urlInstance.protocol === 'node:') {
133133
source = null;
134134
format ??= 'builtin';
135-
} else {
136-
let contextToPass = context;
135+
} else if (format !== 'commonjs' || defaultType === 'module') {
137136
if (source == null) {
138137
({ responseURL, source } = await getSource(urlInstance, context));
139-
contextToPass = { __proto__: context, source };
138+
context = { __proto__: context, source };
140139
}
141140

142-
// Now that we have the source for the module, run `defaultGetFormat` again in case we detect ESM syntax.
143-
format ??= await defaultGetFormat(urlInstance, contextToPass);
141+
if (format == null) {
142+
// Now that we have the source for the module, run `defaultGetFormat` to detect its format.
143+
format = await defaultGetFormat(urlInstance, context);
144144

145-
if (format === 'commonjs' && contextToPass !== context && defaultType !== 'module') {
146-
// For backward compatibility reasons, we need to discard the source in
147-
// order for the CJS loader to re-fetch it.
148-
source = null;
145+
if (format === 'commonjs') {
146+
// For backward compatibility reasons, we need to discard the source in
147+
// order for the CJS loader to re-fetch it.
148+
source = null;
149+
}
149150
}
150151
}
151152

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
const fixtures = require('../common/fixtures');
5+
const assert = require('node:assert');
6+
7+
(async () => {
8+
9+
// Make sure that the CommonJS module lexer has been initialized.
10+
// See https://github.com/nodejs/node/blob/v21.1.0/lib/internal/modules/esm/translators.js#L61-L81.
11+
await import(fixtures.fileURL('empty.js'));
12+
13+
let tickDuringCJSImport = false;
14+
process.nextTick(() => { tickDuringCJSImport = true; });
15+
await import(fixtures.fileURL('empty.cjs'));
16+
17+
assert(!tickDuringCJSImport);
18+
19+
})().then(common.mustCall());
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import '../common/index.mjs';
2+
import fixtures from '../common/fixtures.js';
3+
import assert from 'node:assert';
4+
5+
let tickDuringCJSImport = false;
6+
process.nextTick(() => { tickDuringCJSImport = true; });
7+
await import(fixtures.fileURL('empty.cjs'));
8+
9+
assert(!tickDuringCJSImport);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// Flags: --experimental-loader ./test/fixtures/es-module-loaders/preset-cjs-source.mjs
2+
import '../common/index.mjs';
3+
import * as fixtures from '../common/fixtures.mjs';
4+
import assert from 'assert';
5+
6+
const { default: existingFileSource } = await import(fixtures.fileURL('es-modules', 'cjs-file.cjs'));
7+
const { default: noSuchFileSource } = await import(new URL('./no-such-file.cjs', import.meta.url));
8+
9+
assert.strictEqual(existingFileSource, 'no .cjs file was read to get this source');
10+
assert.strictEqual(noSuchFileSource, 'no .cjs file was read to get this source');

test/fixtures/empty.cjs

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
export function resolve(specifier, context, next) {
2+
if (specifier.endsWith('/no-such-file.cjs')) {
3+
// Shortcut to avoid ERR_MODULE_NOT_FOUND for non-existing file, but keep the url for the load hook.
4+
return {
5+
shortCircuit: true,
6+
url: specifier,
7+
};
8+
}
9+
return next(specifier);
10+
}
11+
12+
export function load(href, context, next) {
13+
if (href.endsWith('.cjs')) {
14+
return {
15+
format: 'commonjs',
16+
shortCircuit: true,
17+
source: 'module.exports = "no .cjs file was read to get this source";',
18+
};
19+
}
20+
return next(href);
21+
}

0 commit comments

Comments
 (0)