module: do not invoke resolve hooks twice for imported cjs · nodejs/node@1519251 · GitHub
Skip to content

Commit 1519251

Browse files
joyeecheungaduh95
authored andcommitted
module: do not invoke resolve hooks twice for imported cjs
Previously the resolve hook can be invoked twice from the synthetic module evaluation step of imported CJS in the extra module._load() call that's invoked on the resolved full path. Add an option to avoid it, since the resolution and loading has already been done before. PR-URL: #61529 Fixes: #57125 Refs: #55808 Refs: #56241 Reviewed-By: Jacob Smith <jacob@frende.me>
1 parent 21b23cd commit 1519251

5 files changed

Lines changed: 59 additions & 11 deletions

File tree

lib/internal/modules/cjs/loader.js

Lines changed: 10 additions & 8 deletions

lib/internal/modules/esm/translators.js

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ translators.set('module', function moduleStrategy(url, translateContext, parentU
113113
});
114114

115115
const { requestTypes: { kRequireInImportedCJS } } = require('internal/modules/esm/utils');
116+
const kShouldSkipModuleHooks = { __proto__: null, shouldSkipModuleHooks: true };
116117
/**
117118
* Loads a CommonJS module via the ESM Loader sync CommonJS translator.
118119
* This translator creates its own version of the `require` function passed into CommonJS modules.
@@ -145,7 +146,9 @@ function loadCJSModule(module, source, url, filename, isMain) {
145146
importAttributes = { __proto__: null, type: 'json' };
146147
break;
147148
case '.node':
148-
return wrapModuleLoad(specifier, module);
149+
// If it gets here in the translators, the hooks must have already been invoked
150+
// in the loader. Skip them in the synthetic module evaluation step.
151+
return wrapModuleLoad(specifier, module, false, kShouldSkipModuleHooks);
149152
default:
150153
// fall through
151154
}
@@ -293,7 +296,9 @@ function createCJSNoSourceModuleWrap(url, parentURL) {
293296
debug(`Loading CJSModule ${url}`);
294297

295298
if (!module.loaded) {
296-
wrapModuleLoad(filename, null, isMain);
299+
// If it gets here in the translators, the hooks must have already been invoked
300+
// in the loader. Skip them in the synthetic module evaluation step.
301+
wrapModuleLoad(filename, null, isMain, kShouldSkipModuleHooks);
297302
}
298303

299304
/** @type {import('./loader').ModuleExports} */
@@ -336,7 +341,9 @@ translators.set('require-commonjs-typescript', (url, translateContext, parentURL
336341
// This goes through Module._load to accommodate monkey-patchers.
337342
function loadCJSModuleWithModuleLoad(module, source, url, filename, isMain) {
338343
assert(module === CJSModule._cache[filename]);
339-
wrapModuleLoad(filename, undefined, isMain);
344+
// If it gets here in the translators, the hooks must have already been invoked
345+
// in the loader. Skip them in the synthetic module evaluation step.
346+
wrapModuleLoad(filename, undefined, isMain, kShouldSkipModuleHooks);
340347
}
341348

342349
// Handle CommonJS modules referenced by `import` statements or expressions,

test/fixtures/value.cjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
exports.value = 42;
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
'use strict';
2+
// Test that load hook in imported CJS only gets invoked once.
3+
4+
const common = require('../common');
5+
const assert = require('assert');
6+
const { registerHooks } = require('module');
7+
const path = require('path');
8+
const { pathToFileURL } = require('url');
9+
10+
const hook = registerHooks({
11+
load: common.mustCall(function(url, context, nextLoad) {
12+
assert.strictEqual(url, pathToFileURL(path.resolve(__dirname, '../fixtures/value.cjs')).href);
13+
return nextLoad(url, context);
14+
}, 1),
15+
});
16+
17+
import('../fixtures/value.cjs').then(common.mustCall((result) => {
18+
assert.strictEqual(result.value, 42);
19+
hook.deregister();
20+
}));
Lines changed: 18 additions & 0 deletions

0 commit comments

Comments
 (0)