Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 0 additions & 14 deletions lib/internal/modules/esm/loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ const {
const {
kIsExecuting,
kRequiredModuleSymbol,
Module: CJSModule,
} = require('internal/modules/cjs/loader');
const { imported_cjs_symbol } = internalBinding('symbols');

Expand Down Expand Up @@ -560,19 +559,6 @@ class ModuleLoader {
throw new ERR_UNKNOWN_MODULE_FORMAT(format, url);
}

// Populate the CJS cache with a facade for ESM in case subsequent require(esm) is
// looking it up from the cache. The parent module of the CJS cache entry would be the
// first CJS module that loads it with require(). This is an approximation, because
// ESM caches more and it does not get re-loaded and updated every time an `import` is
// encountered, unlike CJS require(), and we only use the parent entry to provide
// more information in error messages.
if (format === 'module') {
const parentFilename = urlToFilename(parentURL);
const parent = parentFilename ? CJSModule._cache[parentFilename] : undefined;
const cjsModule = lazyLoadTranslators().cjsEmplaceModuleCacheEntryForURL(url, parent);
debug('cjsEmplaceModuleCacheEntryForURL', url, parent, cjsModule);
}

const result = FunctionPrototypeCall(translator, this, url, source, parentURL === undefined);
assert(result instanceof ModuleWrap);
return result;
Expand Down
19 changes: 16 additions & 3 deletions lib/internal/modules/esm/translators.js
Original file line number Diff line number Diff line change
Expand Up @@ -154,9 +154,22 @@ function loadCJSModule(module, source, url, filename, isMain) {
// requires a separate cache to be populated as well as introducing several quirks. This is not ideal.
const job = cascadedLoader.getModuleJobForRequireInImportedCJS(specifier, url, importAttributes);
job.runSync();
const mod = cjsCache.get(job.url);
assert(mod, `Imported CJS module ${url} failed to load module ${job.url} using require()`);
if (!job.module.synthetic && !mod.loaded) {
let mod = cjsCache.get(job.url);
assert(job.module, `Imported CJS module ${url} failed to load module ${job.url} using require() due to race condition`);

if (job.module.synthetic) {
assert(mod, `Imported CJS module ${url} failed to load module ${job.url} using require() due to missed cache`);
return mod.exports;
}

// The module being required is a source text module.
if (!mod) {
mod = cjsEmplaceModuleCacheEntry(job.url);
cjsCache.set(job.url, mod);
}
// The module has been cached by the re-invented require. Update the exports object
// from the namespace object and return the evaluated exports.
if (!mod.loaded) {
debug('populateCJSExportsFromESM from require(esm) in imported CJS', url, mod, job.module);
populateCJSExportsFromESM(mod, job.module, job.module.getNamespace());
mod.loaded = true;
Expand Down
26 changes: 26 additions & 0 deletions test/es-module/test-esm-in-require-cache-2.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// This tests the behavior of ESM in require.cache when it's loaded from import.

import '../common/index.mjs';
import assert from 'node:assert';
import * as fixtures from '../common/fixtures.mjs';
const filename = fixtures.path('es-modules', 'esm-in-require-cache', 'esm.mjs');
import { Module } from 'node:module';

// Imported ESM should not be in the require cache.
let { name } = await import('../fixtures/es-modules/esm-in-require-cache/import-esm.mjs');
assert.strictEqual(name, 'esm');
assert(!Module._cache[filename]);

({ name } = await import('../fixtures/es-modules/esm-in-require-cache/esm.mjs'));
assert.strictEqual(name, 'esm');
assert(!Module._cache[filename]);

// Requiring ESM indirectly should not put it in the cache.
({ name } = await import('../fixtures/es-modules/esm-in-require-cache/require-import-esm.cjs'));
assert.strictEqual(name, 'esm');
assert(!Module._cache[filename]);

// After being required directly, it should be in the cache.
({ name } = await import('../fixtures/es-modules/esm-in-require-cache/import-require-esm.mjs'));
assert.strictEqual(name, 'esm');
assert(Module._cache[filename]);
25 changes: 25 additions & 0 deletions test/es-module/test-esm-in-require-cache.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// This tests the behavior of ESM in require.cache when it's loaded from require.
'use strict';
require('../common');
const assert = require('node:assert');
const fixtures = require('../common/fixtures');
const filename = fixtures.path('es-modules', 'esm-in-require-cache', 'esm.mjs');

// Requiring ESM indirectly should not put it in the cache.
let { name } = require('../fixtures/es-modules/esm-in-require-cache/import-esm.mjs');
assert.strictEqual(name, 'esm');
assert(!require.cache[filename]);

({ name } = require('../fixtures/es-modules/esm-in-require-cache/require-import-esm.cjs'));
assert.strictEqual(name, 'esm');
assert(!require.cache[filename]);

// After being required directly, it should be in the cache.
({ name } = require('../fixtures/es-modules/esm-in-require-cache/esm.mjs'));
assert.strictEqual(name, 'esm');
assert(require.cache[filename]);
delete require.cache[filename];

({ name } = require('../fixtures/es-modules/esm-in-require-cache/import-require-esm.mjs'));
assert.strictEqual(name, 'esm');
assert(require.cache[filename]);
1 change: 1 addition & 0 deletions test/fixtures/es-modules/esm-in-require-cache/esm.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const name = 'esm';
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { name } from './esm.mjs';
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { name, cache } from './require-esm.cjs'
9 changes: 9 additions & 0 deletions test/fixtures/es-modules/esm-in-require-cache/require-esm.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
const path = require('path');

const name = require('./esm.mjs').name;
exports.name = name;

const filename = path.join(__dirname, 'esm.mjs');
const cache = require.cache[filename];
exports.cache = require.cache[filename];

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
exports.name = require('./import-esm.mjs').name;
Loading