From a915d1de5d83916d717e7203106f160c47979587 Mon Sep 17 00:00:00 2001 From: Sigrid <32902192+s1gr1d@users.noreply.github.com> Date: Tue, 29 Sep 2026 17:01:03 +0200 Subject: [PATCH 1/4] fix(commonjs): unwrap `require()` of external CommonJS modules on Node >= 23 --- packages/commonjs/src/helpers.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/commonjs/src/helpers.js b/packages/commonjs/src/helpers.js index a4c6ca251..dfaa38a25 100644 --- a/packages/commonjs/src/helpers.js +++ b/packages/commonjs/src/helpers.js @@ -38,6 +38,7 @@ export function getDefaultExportFromNamespaceIfPresent (n) { } export function getDefaultExportFromNamespaceIfNotNamed (n) { + if (n && Object.prototype.hasOwnProperty.call(n, 'module.exports')) return n['module.exports']; return n && Object.prototype.hasOwnProperty.call(n, 'default') && Object.keys(n).length === 1 ? n['default'] : n; } From 94a1897fdcc62f9aa93fb4a9ee080a4ae14a375c Mon Sep 17 00:00:00 2001 From: s1gr1d <32902192+s1gr1d@users.noreply.github.com> Date: Tue, 29 Sep 2026 17:22:35 +0200 Subject: [PATCH 2/4] add test --- .../_config.js | 14 ++++ .../main.js | 10 +++ .../external-cjs-node23-constructor/index.js | 10 +++ .../external-cjs-node23-named/index.js | 9 +++ .../commonjs/test/snapshots/function.js.snap | 71 +++++++++++++++++++ 5 files changed, 114 insertions(+) create mode 100644 packages/commonjs/test/fixtures/function/import-cjs-node23-require-returns-default-auto/_config.js create mode 100644 packages/commonjs/test/fixtures/function/import-cjs-node23-require-returns-default-auto/main.js create mode 100644 packages/commonjs/test/node_modules/external-cjs-node23-constructor/index.js create mode 100644 packages/commonjs/test/node_modules/external-cjs-node23-named/index.js diff --git a/packages/commonjs/test/fixtures/function/import-cjs-node23-require-returns-default-auto/_config.js b/packages/commonjs/test/fixtures/function/import-cjs-node23-require-returns-default-auto/_config.js new file mode 100644 index 000000000..d9b2c2c85 --- /dev/null +++ b/packages/commonjs/test/fixtures/function/import-cjs-node23-require-returns-default-auto/_config.js @@ -0,0 +1,14 @@ +// Since Node 23,the namespace of an imported CommonJS module carries a 'module.exports' key, +// so it never has `default` as its only key and the "auto" unwrapping failed. +// https://github.com/nodejs/node/pull/53848 +module.exports = { + description: + 'returns `module.exports` when requiring an external CommonJS module through a Node >= 23 namespace and requireReturnsDefault is "auto"', + options: { + external: ['external-cjs-node23-constructor', 'external-cjs-node23-named'] + }, + pluginOptions: { + requireReturnsDefault: 'auto', + esmExternals: true + } +}; diff --git a/packages/commonjs/test/fixtures/function/import-cjs-node23-require-returns-default-auto/main.js b/packages/commonjs/test/fixtures/function/import-cjs-node23-require-returns-default-auto/main.js new file mode 100644 index 000000000..58eda6b93 --- /dev/null +++ b/packages/commonjs/test/fixtures/function/import-cjs-node23-require-returns-default-auto/main.js @@ -0,0 +1,10 @@ +const ExternalCtor = require('external-cjs-node23-constructor'); +const namedExports = require('external-cjs-node23-named'); + +t.is(typeof ExternalCtor, 'function', 'unwraps `module.exports` instead of returning the namespace'); +t.is(new ExternalCtor('foo').value, 'foo', 'the required value is constructable'); +t.deepEqual( + namedExports, + { foo: 'foo' }, + 'returns `module.exports` even when named exports were detected' +); diff --git a/packages/commonjs/test/node_modules/external-cjs-node23-constructor/index.js b/packages/commonjs/test/node_modules/external-cjs-node23-constructor/index.js new file mode 100644 index 000000000..0d0d3a600 --- /dev/null +++ b/packages/commonjs/test/node_modules/external-cjs-node23-constructor/index.js @@ -0,0 +1,10 @@ +// Fakes the namespace Node >= 23 creates when a CommonJS module is imported: +// the raw `module.exports` value is exposed under a 'module.exports' key: https://github.com/nodejs/node/pull/53848 +Object.defineProperty(exports, '__esModule', { value: true }); + +function ExternalCtor(value) { + this.value = value; +} + +exports.default = ExternalCtor; +exports['module.exports'] = ExternalCtor; diff --git a/packages/commonjs/test/node_modules/external-cjs-node23-named/index.js b/packages/commonjs/test/node_modules/external-cjs-node23-named/index.js new file mode 100644 index 000000000..8553e8201 --- /dev/null +++ b/packages/commonjs/test/node_modules/external-cjs-node23-named/index.js @@ -0,0 +1,9 @@ +// Fakes the Node >= 23 namespace of a CommonJS module whose named exports were detected by cjs-module-lexer: +// named keys next to 'default' and 'module.exports' (https://github.com/nodejs/node/pull/53848). +Object.defineProperty(exports, '__esModule', { value: true }); + +const moduleExports = { foo: 'foo' }; + +exports.default = moduleExports; +exports.foo = 'foo'; +exports['module.exports'] = moduleExports; diff --git a/packages/commonjs/test/snapshots/function.js.snap b/packages/commonjs/test/snapshots/function.js.snap index 1ecce0bb1..d54e55403 100644 --- a/packages/commonjs/test/snapshots/function.js.snap +++ b/packages/commonjs/test/snapshots/function.js.snap @@ -5010,6 +5010,75 @@ module.exports = main; } `; +exports[`import-cjs-node23-require-returns-default-auto 1`] = ` +{ + "main.js": "'use strict'; + +var externalCjsNode23Constructor = require('external-cjs-node23-constructor'); +var externalCjsNode23Named = require('external-cjs-node23-named'); + +function _interopNamespaceCompat(e) { + if (e && typeof e === 'object' && 'default' in e) return e; + var n = Object.create(null); + if (e) { + Object.keys(e).forEach(function (k) { + if (k !== 'default') { + var d = Object.getOwnPropertyDescriptor(e, k); + Object.defineProperty(n, k, d.get ? d : { + enumerable: true, + get: function () { return e[k]; } + }); + } + }); + } + n.default = e; + return Object.freeze(n); +} + +var externalCjsNode23Constructor__namespace = /*#__PURE__*/_interopNamespaceCompat(externalCjsNode23Constructor); +var externalCjsNode23Named__namespace = /*#__PURE__*/_interopNamespaceCompat(externalCjsNode23Named); + +function getDefaultExportFromCjs (x) { + return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; +} + +function getDefaultExportFromNamespaceIfNotNamed (n) { + if (n && Object.prototype.hasOwnProperty.call(n, 'module.exports')) return n['module.exports']; + return n && Object.prototype.hasOwnProperty.call(n, 'default') && Object.keys(n).length === 1 ? n['default'] : n; +} + +var main$1 = {}; + +var require$$0 = /*@__PURE__*/getDefaultExportFromNamespaceIfNotNamed(externalCjsNode23Constructor__namespace); + +var require$$1 = /*@__PURE__*/getDefaultExportFromNamespaceIfNotNamed(externalCjsNode23Named__namespace); + +var hasRequiredMain; + +function requireMain () { + if (hasRequiredMain) return main$1; + hasRequiredMain = 1; + const ExternalCtor = require$$0; + const namedExports = require$$1; + + t.is(typeof ExternalCtor, 'function', 'unwraps \`module.exports\` instead of returning the namespace'); + t.is(new ExternalCtor('foo').value, 'foo', 'the required value is constructable'); + t.deepEqual( + namedExports, + { foo: 'foo' }, + 'returns \`module.exports\` even when named exports were detected' + ); + return main$1; +} + +var mainExports = requireMain(); +var main = /*@__PURE__*/getDefaultExportFromCjs(mainExports); + +module.exports = main; +", +} +`; + exports[`import-esm-require-returns-default-auto 1`] = ` { "main.js": "'use strict'; @@ -5045,6 +5114,7 @@ function getDefaultExportFromCjs (x) { } function getDefaultExportFromNamespaceIfNotNamed (n) { + if (n && Object.prototype.hasOwnProperty.call(n, 'module.exports')) return n['module.exports']; return n && Object.prototype.hasOwnProperty.call(n, 'default') && Object.keys(n).length === 1 ? n['default'] : n; } @@ -5503,6 +5573,7 @@ function getDefaultExportFromCjs (x) { } function getDefaultExportFromNamespaceIfNotNamed (n) { + if (n && Object.prototype.hasOwnProperty.call(n, 'module.exports')) return n['module.exports']; return n && Object.prototype.hasOwnProperty.call(n, 'default') && Object.keys(n).length === 1 ? n['default'] : n; } From 0ff00919a07de20b7243558c7b18db4eeac51f35 Mon Sep 17 00:00:00 2001 From: s1gr1d <32902192+s1gr1d@users.noreply.github.com> Date: Tue, 29 Sep 2026 17:32:09 +0200 Subject: [PATCH 3/4] address comments --- packages/commonjs/README.md | 8 +++++++- packages/commonjs/src/helpers.js | 7 ++++++- .../_config.js | 6 +++++- .../main.js | 6 ++++++ .../external-esm-module-exports-key/index.js | 8 ++++++++ .../commonjs/test/snapshots/function.js.snap | 16 +++++++++++++--- 6 files changed, 45 insertions(+), 6 deletions(-) create mode 100644 packages/commonjs/test/node_modules/external-esm-module-exports-key/index.js diff --git a/packages/commonjs/README.md b/packages/commonjs/README.md index 53afe5217..820f8813f 100644 --- a/packages/commonjs/README.md +++ b/packages/commonjs/README.md @@ -375,13 +375,19 @@ For these situations, you can change Rollup's behaviour either globally or per m console.log(dep); ``` -- `"auto"`: This is complementary to how [`output.exports`](https://rollupjs.org/guide/en/#outputexports): `"auto"` works in Rollup: If a module has a default export and no named exports, requiring that module returns the default export. In all other cases, the namespace is returned. For external dependencies when using `esmExternals: true`, a corresponding interop helper is added: +- `"auto"`: This is complementary to how [`output.exports`](https://rollupjs.org/guide/en/#outputexports): `"auto"` works in Rollup: If a module has a default export and no named exports, requiring that module returns the default export. In all other cases, the namespace is returned. One exception are namespaces of CommonJS modules imported on Node >= 23: They expose the raw `module.exports` value under a `'module.exports'` key ([nodejs/node#53848](https://github.com/nodejs/node/pull/53848)), and requiring such a module returns that value, just like a real `require()` call would. For external dependencies when using `esmExternals: true`, a corresponding interop helper is added: ```js // output import * as dep$1 from 'dep'; function getDefaultExportFromNamespaceIfNotNamed(n) { + if ( + n && + Object.prototype.hasOwnProperty.call(n, 'module.exports') && + n['default'] === n['module.exports'] + ) + return n['module.exports']; return n && Object.prototype.hasOwnProperty.call(n, 'default') && Object.keys(n).length === 1 ? n['default'] : n; diff --git a/packages/commonjs/src/helpers.js b/packages/commonjs/src/helpers.js index dfaa38a25..97539bbb2 100644 --- a/packages/commonjs/src/helpers.js +++ b/packages/commonjs/src/helpers.js @@ -26,6 +26,11 @@ export const IS_WRAPPED_COMMONJS = 'withRequireFunction'; // Minifiers like uglify will usually transpile it back if compatibility with ES3 is not enabled. // This could be improved by inspecting Rollup's "generatedCode" option +// Since Node 23, the namespace of an imported CommonJS module exposes the raw `module.exports` +// value under a 'module.exports' key whose value is identical to the `default` (https://github.com/nodejs/node/pull/53848). +// `getDefaultExportFromNamespaceIfNotNamed` returns it to match what a real `require()` call would return. +// The identity check keeps namespaces of ES modules that just export a binding named 'module.exports' intact. + const HELPERS = ` export var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; @@ -38,7 +43,7 @@ export function getDefaultExportFromNamespaceIfPresent (n) { } export function getDefaultExportFromNamespaceIfNotNamed (n) { - if (n && Object.prototype.hasOwnProperty.call(n, 'module.exports')) return n['module.exports']; + if (n && Object.prototype.hasOwnProperty.call(n, 'module.exports') && n['default'] === n['module.exports']) return n['module.exports']; return n && Object.prototype.hasOwnProperty.call(n, 'default') && Object.keys(n).length === 1 ? n['default'] : n; } diff --git a/packages/commonjs/test/fixtures/function/import-cjs-node23-require-returns-default-auto/_config.js b/packages/commonjs/test/fixtures/function/import-cjs-node23-require-returns-default-auto/_config.js index d9b2c2c85..0bf96aa49 100644 --- a/packages/commonjs/test/fixtures/function/import-cjs-node23-require-returns-default-auto/_config.js +++ b/packages/commonjs/test/fixtures/function/import-cjs-node23-require-returns-default-auto/_config.js @@ -5,7 +5,11 @@ module.exports = { description: 'returns `module.exports` when requiring an external CommonJS module through a Node >= 23 namespace and requireReturnsDefault is "auto"', options: { - external: ['external-cjs-node23-constructor', 'external-cjs-node23-named'] + external: [ + 'external-cjs-node23-constructor', + 'external-cjs-node23-named', + 'external-esm-module-exports-key' + ] }, pluginOptions: { requireReturnsDefault: 'auto', diff --git a/packages/commonjs/test/fixtures/function/import-cjs-node23-require-returns-default-auto/main.js b/packages/commonjs/test/fixtures/function/import-cjs-node23-require-returns-default-auto/main.js index 58eda6b93..b109718e4 100644 --- a/packages/commonjs/test/fixtures/function/import-cjs-node23-require-returns-default-auto/main.js +++ b/packages/commonjs/test/fixtures/function/import-cjs-node23-require-returns-default-auto/main.js @@ -1,5 +1,6 @@ const ExternalCtor = require('external-cjs-node23-constructor'); const namedExports = require('external-cjs-node23-named'); +const esmNamespace = require('external-esm-module-exports-key'); t.is(typeof ExternalCtor, 'function', 'unwraps `module.exports` instead of returning the namespace'); t.is(new ExternalCtor('foo').value, 'foo', 'the required value is constructable'); @@ -8,3 +9,8 @@ t.deepEqual( { foo: 'foo' }, 'returns `module.exports` even when named exports were detected' ); +t.deepEqual( + esmNamespace, + { default: 'bar', foo: 'foo', 'module.exports': 'not-the-default' }, + 'keeps the namespace of an ES module that exports a binding named "module.exports"' +); diff --git a/packages/commonjs/test/node_modules/external-esm-module-exports-key/index.js b/packages/commonjs/test/node_modules/external-esm-module-exports-key/index.js new file mode 100644 index 000000000..72d328378 --- /dev/null +++ b/packages/commonjs/test/node_modules/external-esm-module-exports-key/index.js @@ -0,0 +1,8 @@ +// Fakes a genuine ES module that exports a binding literally named 'module.exports' +// (`export { x as 'module.exports' }`). Unlike a Node >= 23 CommonJS namespace, its value +// differs from `default`, so "auto" must keep returning the namespace. +Object.defineProperty(exports, '__esModule', { value: true }); + +exports.default = 'bar'; +exports.foo = 'foo'; +exports['module.exports'] = 'not-the-default'; diff --git a/packages/commonjs/test/snapshots/function.js.snap b/packages/commonjs/test/snapshots/function.js.snap index d54e55403..e6f058e82 100644 --- a/packages/commonjs/test/snapshots/function.js.snap +++ b/packages/commonjs/test/snapshots/function.js.snap @@ -5016,6 +5016,7 @@ exports[`import-cjs-node23-require-returns-default-auto 1`] = ` var externalCjsNode23Constructor = require('external-cjs-node23-constructor'); var externalCjsNode23Named = require('external-cjs-node23-named'); +var externalEsmModuleExportsKey = require('external-esm-module-exports-key'); function _interopNamespaceCompat(e) { if (e && typeof e === 'object' && 'default' in e) return e; @@ -5037,13 +5038,14 @@ function _interopNamespaceCompat(e) { var externalCjsNode23Constructor__namespace = /*#__PURE__*/_interopNamespaceCompat(externalCjsNode23Constructor); var externalCjsNode23Named__namespace = /*#__PURE__*/_interopNamespaceCompat(externalCjsNode23Named); +var externalEsmModuleExportsKey__namespace = /*#__PURE__*/_interopNamespaceCompat(externalEsmModuleExportsKey); function getDefaultExportFromCjs (x) { return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; } function getDefaultExportFromNamespaceIfNotNamed (n) { - if (n && Object.prototype.hasOwnProperty.call(n, 'module.exports')) return n['module.exports']; + if (n && Object.prototype.hasOwnProperty.call(n, 'module.exports') && n['default'] === n['module.exports']) return n['module.exports']; return n && Object.prototype.hasOwnProperty.call(n, 'default') && Object.keys(n).length === 1 ? n['default'] : n; } @@ -5053,6 +5055,8 @@ var require$$0 = /*@__PURE__*/getDefaultExportFromNamespaceIfNotNamed(externalCj var require$$1 = /*@__PURE__*/getDefaultExportFromNamespaceIfNotNamed(externalCjsNode23Named__namespace); +var require$$2 = /*@__PURE__*/getDefaultExportFromNamespaceIfNotNamed(externalEsmModuleExportsKey__namespace); + var hasRequiredMain; function requireMain () { @@ -5060,6 +5064,7 @@ function requireMain () { hasRequiredMain = 1; const ExternalCtor = require$$0; const namedExports = require$$1; + const esmNamespace = require$$2; t.is(typeof ExternalCtor, 'function', 'unwraps \`module.exports\` instead of returning the namespace'); t.is(new ExternalCtor('foo').value, 'foo', 'the required value is constructable'); @@ -5068,6 +5073,11 @@ function requireMain () { { foo: 'foo' }, 'returns \`module.exports\` even when named exports were detected' ); + t.deepEqual( + esmNamespace, + { default: 'bar', foo: 'foo', 'module.exports': 'not-the-default' }, + 'keeps the namespace of an ES module that exports a binding named "module.exports"' + ); return main$1; } @@ -5114,7 +5124,7 @@ function getDefaultExportFromCjs (x) { } function getDefaultExportFromNamespaceIfNotNamed (n) { - if (n && Object.prototype.hasOwnProperty.call(n, 'module.exports')) return n['module.exports']; + if (n && Object.prototype.hasOwnProperty.call(n, 'module.exports') && n['default'] === n['module.exports']) return n['module.exports']; return n && Object.prototype.hasOwnProperty.call(n, 'default') && Object.keys(n).length === 1 ? n['default'] : n; } @@ -5573,7 +5583,7 @@ function getDefaultExportFromCjs (x) { } function getDefaultExportFromNamespaceIfNotNamed (n) { - if (n && Object.prototype.hasOwnProperty.call(n, 'module.exports')) return n['module.exports']; + if (n && Object.prototype.hasOwnProperty.call(n, 'module.exports') && n['default'] === n['module.exports']) return n['module.exports']; return n && Object.prototype.hasOwnProperty.call(n, 'default') && Object.keys(n).length === 1 ? n['default'] : n; } From bb81eda12dc186b29644a9253ebc0389f01236c1 Mon Sep 17 00:00:00 2001 From: s1gr1d <32902192+s1gr1d@users.noreply.github.com> Date: Tue, 29 Sep 2026 17:52:56 +0200 Subject: [PATCH 4/4] address comment --- packages/commonjs/README.md | 11 ++++----- packages/commonjs/src/helpers.js | 8 +++++-- .../_config.js | 1 + .../main.js | 2 ++ .../external-cjs-node23-nan/index.js | 6 +++++ .../commonjs/test/snapshots/function.js.snap | 24 ++++++++++++++++--- 6 files changed, 41 insertions(+), 11 deletions(-) create mode 100644 packages/commonjs/test/node_modules/external-cjs-node23-nan/index.js diff --git a/packages/commonjs/README.md b/packages/commonjs/README.md index 820f8813f..9212ed941 100644 --- a/packages/commonjs/README.md +++ b/packages/commonjs/README.md @@ -382,12 +382,11 @@ For these situations, you can change Rollup's behaviour either globally or per m import * as dep$1 from 'dep'; function getDefaultExportFromNamespaceIfNotNamed(n) { - if ( - n && - Object.prototype.hasOwnProperty.call(n, 'module.exports') && - n['default'] === n['module.exports'] - ) - return n['module.exports']; + if (n && Object.prototype.hasOwnProperty.call(n, 'module.exports')) { + var d = n['default']; + var m = n['module.exports']; + if (d === m || (d !== d && m !== m)) return m; + } return n && Object.prototype.hasOwnProperty.call(n, 'default') && Object.keys(n).length === 1 ? n['default'] : n; diff --git a/packages/commonjs/src/helpers.js b/packages/commonjs/src/helpers.js index 97539bbb2..aec76cf65 100644 --- a/packages/commonjs/src/helpers.js +++ b/packages/commonjs/src/helpers.js @@ -29,7 +29,7 @@ export const IS_WRAPPED_COMMONJS = 'withRequireFunction'; // Since Node 23, the namespace of an imported CommonJS module exposes the raw `module.exports` // value under a 'module.exports' key whose value is identical to the `default` (https://github.com/nodejs/node/pull/53848). // `getDefaultExportFromNamespaceIfNotNamed` returns it to match what a real `require()` call would return. -// The identity check keeps namespaces of ES modules that just export a binding named 'module.exports' intact. +// The same-value check (NaN-safe, hence the self-comparisons) keeps namespaces of ES modulesthat just export a binding named 'module.exports' intact. const HELPERS = ` export var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; @@ -43,7 +43,11 @@ export function getDefaultExportFromNamespaceIfPresent (n) { } export function getDefaultExportFromNamespaceIfNotNamed (n) { - if (n && Object.prototype.hasOwnProperty.call(n, 'module.exports') && n['default'] === n['module.exports']) return n['module.exports']; + if (n && Object.prototype.hasOwnProperty.call(n, 'module.exports')) { + var d = n['default']; + var m = n['module.exports']; + if (d === m || (d !== d && m !== m)) return m; + } return n && Object.prototype.hasOwnProperty.call(n, 'default') && Object.keys(n).length === 1 ? n['default'] : n; } diff --git a/packages/commonjs/test/fixtures/function/import-cjs-node23-require-returns-default-auto/_config.js b/packages/commonjs/test/fixtures/function/import-cjs-node23-require-returns-default-auto/_config.js index 0bf96aa49..b1a9068fb 100644 --- a/packages/commonjs/test/fixtures/function/import-cjs-node23-require-returns-default-auto/_config.js +++ b/packages/commonjs/test/fixtures/function/import-cjs-node23-require-returns-default-auto/_config.js @@ -8,6 +8,7 @@ module.exports = { external: [ 'external-cjs-node23-constructor', 'external-cjs-node23-named', + 'external-cjs-node23-nan', 'external-esm-module-exports-key' ] }, diff --git a/packages/commonjs/test/fixtures/function/import-cjs-node23-require-returns-default-auto/main.js b/packages/commonjs/test/fixtures/function/import-cjs-node23-require-returns-default-auto/main.js index b109718e4..97a90c99a 100644 --- a/packages/commonjs/test/fixtures/function/import-cjs-node23-require-returns-default-auto/main.js +++ b/packages/commonjs/test/fixtures/function/import-cjs-node23-require-returns-default-auto/main.js @@ -1,6 +1,7 @@ const ExternalCtor = require('external-cjs-node23-constructor'); const namedExports = require('external-cjs-node23-named'); const esmNamespace = require('external-esm-module-exports-key'); +const nanExport = require('external-cjs-node23-nan'); t.is(typeof ExternalCtor, 'function', 'unwraps `module.exports` instead of returning the namespace'); t.is(new ExternalCtor('foo').value, 'foo', 'the required value is constructable'); @@ -14,3 +15,4 @@ t.deepEqual( { default: 'bar', foo: 'foo', 'module.exports': 'not-the-default' }, 'keeps the namespace of an ES module that exports a binding named "module.exports"' ); +t.is(nanExport, NaN, 'unwraps `module.exports` when the exported value is NaN'); diff --git a/packages/commonjs/test/node_modules/external-cjs-node23-nan/index.js b/packages/commonjs/test/node_modules/external-cjs-node23-nan/index.js new file mode 100644 index 000000000..557f16396 --- /dev/null +++ b/packages/commonjs/test/node_modules/external-cjs-node23-nan/index.js @@ -0,0 +1,6 @@ +// Fakes the Node >= 23 namespace of a CommonJS module that exports NaN: +// `default` and 'module.exports' hold the same value, but NaN === NaN is false. +Object.defineProperty(exports, '__esModule', { value: true }); + +exports.default = NaN; +exports['module.exports'] = NaN; diff --git a/packages/commonjs/test/snapshots/function.js.snap b/packages/commonjs/test/snapshots/function.js.snap index e6f058e82..fb34e9e65 100644 --- a/packages/commonjs/test/snapshots/function.js.snap +++ b/packages/commonjs/test/snapshots/function.js.snap @@ -5017,6 +5017,7 @@ exports[`import-cjs-node23-require-returns-default-auto 1`] = ` var externalCjsNode23Constructor = require('external-cjs-node23-constructor'); var externalCjsNode23Named = require('external-cjs-node23-named'); var externalEsmModuleExportsKey = require('external-esm-module-exports-key'); +var externalCjsNode23Nan = require('external-cjs-node23-nan'); function _interopNamespaceCompat(e) { if (e && typeof e === 'object' && 'default' in e) return e; @@ -5039,13 +5040,18 @@ function _interopNamespaceCompat(e) { var externalCjsNode23Constructor__namespace = /*#__PURE__*/_interopNamespaceCompat(externalCjsNode23Constructor); var externalCjsNode23Named__namespace = /*#__PURE__*/_interopNamespaceCompat(externalCjsNode23Named); var externalEsmModuleExportsKey__namespace = /*#__PURE__*/_interopNamespaceCompat(externalEsmModuleExportsKey); +var externalCjsNode23Nan__namespace = /*#__PURE__*/_interopNamespaceCompat(externalCjsNode23Nan); function getDefaultExportFromCjs (x) { return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; } function getDefaultExportFromNamespaceIfNotNamed (n) { - if (n && Object.prototype.hasOwnProperty.call(n, 'module.exports') && n['default'] === n['module.exports']) return n['module.exports']; + if (n && Object.prototype.hasOwnProperty.call(n, 'module.exports')) { + var d = n['default']; + var m = n['module.exports']; + if (d === m || (d !== d && m !== m)) return m; + } return n && Object.prototype.hasOwnProperty.call(n, 'default') && Object.keys(n).length === 1 ? n['default'] : n; } @@ -5057,6 +5063,8 @@ var require$$1 = /*@__PURE__*/getDefaultExportFromNamespaceIfNotNamed(externalCj var require$$2 = /*@__PURE__*/getDefaultExportFromNamespaceIfNotNamed(externalEsmModuleExportsKey__namespace); +var require$$3 = /*@__PURE__*/getDefaultExportFromNamespaceIfNotNamed(externalCjsNode23Nan__namespace); + var hasRequiredMain; function requireMain () { @@ -5065,6 +5073,7 @@ function requireMain () { const ExternalCtor = require$$0; const namedExports = require$$1; const esmNamespace = require$$2; + const nanExport = require$$3; t.is(typeof ExternalCtor, 'function', 'unwraps \`module.exports\` instead of returning the namespace'); t.is(new ExternalCtor('foo').value, 'foo', 'the required value is constructable'); @@ -5078,6 +5087,7 @@ function requireMain () { { default: 'bar', foo: 'foo', 'module.exports': 'not-the-default' }, 'keeps the namespace of an ES module that exports a binding named "module.exports"' ); + t.is(nanExport, NaN, 'unwraps \`module.exports\` when the exported value is NaN'); return main$1; } @@ -5124,7 +5134,11 @@ function getDefaultExportFromCjs (x) { } function getDefaultExportFromNamespaceIfNotNamed (n) { - if (n && Object.prototype.hasOwnProperty.call(n, 'module.exports') && n['default'] === n['module.exports']) return n['module.exports']; + if (n && Object.prototype.hasOwnProperty.call(n, 'module.exports')) { + var d = n['default']; + var m = n['module.exports']; + if (d === m || (d !== d && m !== m)) return m; + } return n && Object.prototype.hasOwnProperty.call(n, 'default') && Object.keys(n).length === 1 ? n['default'] : n; } @@ -5583,7 +5597,11 @@ function getDefaultExportFromCjs (x) { } function getDefaultExportFromNamespaceIfNotNamed (n) { - if (n && Object.prototype.hasOwnProperty.call(n, 'module.exports') && n['default'] === n['module.exports']) return n['module.exports']; + if (n && Object.prototype.hasOwnProperty.call(n, 'module.exports')) { + var d = n['default']; + var m = n['module.exports']; + if (d === m || (d !== d && m !== m)) return m; + } return n && Object.prototype.hasOwnProperty.call(n, 'default') && Object.keys(n).length === 1 ? n['default'] : n; }