Skip to content

Commit d24c731

Browse files
committed
module: support 'module.exports' interop export in require(esm)
PR-URL: #54563 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
1 parent 2755551 commit d24c731

File tree

54 files changed

+308
-6
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+308
-6
lines changed

β€Ždoc/api/modules.md

+64-2

β€Žlib/internal/modules/cjs/loader.js

+7-4
Original file line numberDiff line numberDiff line change
@@ -1427,10 +1427,13 @@ function loadESMFromCJS(mod, filename) {
14271427
// createRequiredModuleFacade() to `wrap` which is a ModuleWrap wrapping
14281428
// over the original module.
14291429

1430-
// We don't do this to modules that don't have default exports to avoid
1431-
// the unnecessary overhead. If __esModule is already defined, we will
1432-
// also skip the extension to allow users to override it.
1433-
if (!ObjectHasOwn(namespace, 'default') || ObjectHasOwn(namespace, '__esModule')) {
1430+
// We don't do this to modules that are marked as CJS ESM or that
1431+
// don't have default exports to avoid the unnecessary overhead.
1432+
// If __esModule is already defined, we will also skip the extension
1433+
// to allow users to override it.
1434+
if (ObjectHasOwn(namespace, 'module.exports')) {
1435+
mod.exports = namespace['module.exports'];
1436+
} else if (!ObjectHasOwn(namespace, 'default') || ObjectHasOwn(namespace, '__esModule')) {
14341437
mod.exports = namespace;
14351438
} else {
14361439
mod.exports = createRequiredModuleFacade(wrap);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// Flags: --experimental-require-module
2+
import '../common/index.mjs';
3+
import assert from 'assert';
4+
import { directRequireFixture, importFixture } from '../fixtures/pkgexports.mjs';
5+
6+
const tests = {
7+
'false': false,
8+
'string': 'cjs',
9+
'object': { a: 'cjs a', b: 'cjs b' },
10+
'fauxesmdefault': { default: 'faux esm default' },
11+
'fauxesmmixed': { default: 'faux esm default', a: 'faux esm a', b: 'faux esm b' },
12+
'fauxesmnamed': { a: 'faux esm a', b: 'faux esm b' }
13+
};
14+
15+
// This test demonstrates interop between CJS and CJS represented as ESM
16+
// under the new `export { ... as 'module.exports'}` pattern, for the above cases.
17+
for (const [test, exactShape] of Object.entries(tests)) {
18+
// Each case represents a CJS dependency, which has the expected shape in CJS:
19+
assert.deepStrictEqual(directRequireFixture(`interop-cjsdep-${test}`), exactShape);
20+
21+
// Each dependency is reexported through CJS as if it is a library being consumed,
22+
// which in CJS is fully shape-preserving:
23+
assert.deepStrictEqual(directRequireFixture(`interop-cjs/${test}`), exactShape);
24+
25+
// Now we have ESM conversions of these dependencies, using `export ... as "module.exports"`
26+
// staring with the conversion of those dependencies into ESM under require(esm):
27+
assert.deepStrictEqual(directRequireFixture(`interop-cjsdep-${test}-esm`), exactShape);
28+
29+
// When importing these ESM conversions, from require(esm), we should preserve the shape:
30+
assert.deepStrictEqual(directRequireFixture(`interop-cjs/${test}-esm`), exactShape);
31+
32+
// Now if the importer itself is converted into ESM, it should still be able to load the original
33+
// CJS and reexport it, preserving the shape:
34+
assert.deepStrictEqual(directRequireFixture(`interop-cjs-esm/${test}`), exactShape);
35+
36+
// And then if we have the converted CJS to ESM importing from converted CJS to ESM,
37+
// that should also work:
38+
assert.deepStrictEqual(directRequireFixture(`interop-cjs-esm/${test}-esm`), exactShape);
39+
40+
// Finally, the CJS ESM representation under `import()` should match all these cases equivalently,
41+
// where the CJS module is exported as the default export:
42+
const esmCjsImport = await importFixture(`interop-cjsdep-${test}`);
43+
assert.deepStrictEqual(esmCjsImport.default, exactShape);
44+
45+
assert.deepStrictEqual((await importFixture(`interop-cjsdep-${test}`)).default, exactShape);
46+
assert.deepStrictEqual((await importFixture(`interop-cjs/${test}`)).default, exactShape);
47+
assert.deepStrictEqual((await importFixture(`interop-cjsdep-${test}-esm`)).default, exactShape);
48+
assert.deepStrictEqual((await importFixture(`interop-cjs/${test}-esm`)).default, exactShape);
49+
assert.deepStrictEqual((await importFixture(`interop-cjs-esm/${test}`)).default, exactShape);
50+
assert.deepStrictEqual((await importFixture(`interop-cjs-esm/${test}-esm`)).default, exactShape);
51+
}

β€Žtest/fixtures/node_modules/interop-cjs-esm/false-esm.js

+3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žtest/fixtures/node_modules/interop-cjs-esm/false.js

+3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žtest/fixtures/node_modules/interop-cjs-esm/fauxesmdefault-esm.js

+3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žtest/fixtures/node_modules/interop-cjs-esm/fauxesmdefault.js

+3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žtest/fixtures/node_modules/interop-cjs-esm/fauxesmmixed-esm.js

+4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žtest/fixtures/node_modules/interop-cjs-esm/fauxesmmixed.js

+3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žtest/fixtures/node_modules/interop-cjs-esm/fauxesmnamed-esm.js

+3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žtest/fixtures/node_modules/interop-cjs-esm/fauxesmnamed.js

+3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žtest/fixtures/node_modules/interop-cjs-esm/object-esm.js

+3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žtest/fixtures/node_modules/interop-cjs-esm/object.js

+3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žtest/fixtures/node_modules/interop-cjs-esm/package.json

+17
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žtest/fixtures/node_modules/interop-cjs-esm/string-esm.js

+3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žtest/fixtures/node_modules/interop-cjs-esm/string.js

+3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žtest/fixtures/node_modules/interop-cjs/false-esm.js

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žtest/fixtures/node_modules/interop-cjs/false.js

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žtest/fixtures/node_modules/interop-cjs/fauxesmdefault-esm.js

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žtest/fixtures/node_modules/interop-cjs/fauxesmdefault.js

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žtest/fixtures/node_modules/interop-cjs/fauxesmmixed-esm.js

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žtest/fixtures/node_modules/interop-cjs/fauxesmmixed.js

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žtest/fixtures/node_modules/interop-cjs/fauxesmnamed-esm.js

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žtest/fixtures/node_modules/interop-cjs/fauxesmnamed.js

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žtest/fixtures/node_modules/interop-cjs/object-esm.js

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žtest/fixtures/node_modules/interop-cjs/object.js

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žtest/fixtures/node_modules/interop-cjs/package.json

+17
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žtest/fixtures/node_modules/interop-cjs/string-esm.js

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žtest/fixtures/node_modules/interop-cjs/string.js

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žtest/fixtures/node_modules/interop-cjsdep-false-esm/dep.js

+3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žtest/fixtures/node_modules/interop-cjsdep-false-esm/package.json

+4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žtest/fixtures/node_modules/interop-cjsdep-false/dep.js

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žtest/fixtures/node_modules/interop-cjsdep-false/package.json

+4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žtest/fixtures/node_modules/interop-cjsdep-fauxesmdefault-esm/dep.js

+7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žtest/fixtures/node_modules/interop-cjsdep-fauxesmdefault-esm/package.json

+4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žtest/fixtures/node_modules/interop-cjsdep-fauxesmdefault/dep.js

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žtest/fixtures/node_modules/interop-cjsdep-fauxesmdefault/package.json

+4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žtest/fixtures/node_modules/interop-cjsdep-fauxesmmixed-esm/dep.js

+9
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žtest/fixtures/node_modules/interop-cjsdep-fauxesmmixed-esm/package.json

+4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žtest/fixtures/node_modules/interop-cjsdep-fauxesmmixed/dep.js

+4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žtest/fixtures/node_modules/interop-cjsdep-fauxesmmixed/package.json

+4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žtest/fixtures/node_modules/interop-cjsdep-fauxesmnamed-esm/dep.js

+8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žtest/fixtures/node_modules/interop-cjsdep-fauxesmnamed-esm/package.json

+4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žtest/fixtures/node_modules/interop-cjsdep-fauxesmnamed/dep.js

+3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žtest/fixtures/node_modules/interop-cjsdep-fauxesmnamed/package.json

+4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žtest/fixtures/node_modules/interop-cjsdep-object-esm/dep.js

+8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žtest/fixtures/node_modules/interop-cjsdep-object-esm/package.json

+4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žtest/fixtures/node_modules/interop-cjsdep-object/dep.js

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žtest/fixtures/node_modules/interop-cjsdep-object/package.json

+4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žtest/fixtures/node_modules/interop-cjsdep-string-esm/dep.js

+3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žtest/fixtures/node_modules/interop-cjsdep-string-esm/package.json

+4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žtest/fixtures/node_modules/interop-cjsdep-string/dep.js

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žtest/fixtures/node_modules/interop-cjsdep-string/package.json

+4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
Β (0)