-
Notifications
You must be signed in to change notification settings - Fork 30k
Commit
This patch implements a "module-sync" exports condition for packages to supply a sycnrhonous ES module to the Node.js module loader, no matter it's being required or imported. This is similar to the "module" condition that bundlers have been using to support `require(esm)` in Node.js, and allows dual-package authors to opt into ESM-first only newer versions of Node.js that supports require(esm) while avoiding the dual-package hazard. ```json { "type": "module", "exports": { "node": { // On new version of Node.js, both require() and import get // the ESM version "module-sync": "./index.js", // On older version of Node.js, where "module" and // require(esm) are not supported, use the transpiled CJS version // to avoid dual-package hazard. Library authors can decide // to drop support for older versions of Node.js when they think // it's time. "default": "./dist/index.cjs" }, // On any other environment, use the ESM version. "default": "./index.js" } } ``` We end up implementing a condition with a different name instead of reusing "module", because existing code in the ecosystem using the "module" condition sometimes also expect the module resolution for these ESM files to work in CJS style, which is supported by bundlers, but the native Node.js loader has intentionally made ESM resolution different from CJS resolution (e.g. forbidding `import './noext'` or `import './directory'`), so it would be semver-major to implement a `"module"` condition without implementing the forbidden ESM resolution rules. For now, this just implments a new condition as semver-minor so it can be backported to older LTS. Refs: https://webpack.js.org/guides/package-exports/#target-environment-independent-packages PR-URL: #54648 Fixes: #52173 Refs: https://github.com/joyeecheung/test-module-condition Refs: #52697 Reviewed-By: Jacob Smith <[email protected]> Reviewed-By: Jan Krems <[email protected]> Reviewed-By: Chengzhong Wu <[email protected]>
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
// Flags: --experimental-require-module | ||
|
||
import '../common/index.mjs'; | ||
import assert from 'node:assert'; | ||
import * as staticImport from '../fixtures/es-modules/module-condition/import.mjs'; | ||
import { import as _import } from '../fixtures/es-modules/module-condition/dynamic_import.js'; | ||
|
||
async function dynamicImport(id) { | ||
const result = await _import(id); | ||
return result.resolved; | ||
} | ||
|
||
assert.deepStrictEqual({ ...staticImport }, { | ||
import_module_require: 'import', | ||
module_and_import: 'module', | ||
module_and_require: 'module', | ||
module_import_require: 'module', | ||
module_only: 'module', | ||
module_require_import: 'module', | ||
require_module_import: 'module', | ||
}); | ||
|
||
assert.strictEqual(await dynamicImport('import-module-require'), 'import'); | ||
assert.strictEqual(await dynamicImport('module-and-import'), 'module'); | ||
assert.strictEqual(await dynamicImport('module-and-require'), 'module'); | ||
assert.strictEqual(await dynamicImport('module-import-require'), 'module'); | ||
assert.strictEqual(await dynamicImport('module-only'), 'module'); | ||
assert.strictEqual(await dynamicImport('module-require-import'), 'module'); | ||
assert.strictEqual(await dynamicImport('require-module-import'), 'module'); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
// Flags: --experimental-require-module | ||
'use strict'; | ||
|
||
require('../common'); | ||
const assert = require('assert'); | ||
|
||
const loader = require('../fixtures/es-modules/module-condition/require.cjs'); | ||
|
||
assert.strictEqual(loader.require('import-module-require').resolved, 'module'); | ||
assert.strictEqual(loader.require('module-and-import').resolved, 'module'); | ||
assert.strictEqual(loader.require('module-and-require').resolved, 'module'); | ||
assert.strictEqual(loader.require('module-import-require').resolved, 'module'); | ||
assert.strictEqual(loader.require('module-only').resolved, 'module'); | ||
assert.strictEqual(loader.require('module-require-import').resolved, 'module'); | ||
assert.strictEqual(loader.require('require-module-import').resolved, 'require'); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
function load(id) { | ||
return import(id); | ||
} | ||
|
||
export { load as import }; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
export { resolved as import_module_require } from 'import-module-require'; | ||
export { resolved as module_and_import } from 'module-and-import'; | ||
export { resolved as module_and_require } from 'module-and-require'; | ||
export { resolved as module_import_require } from 'module-import-require'; | ||
export { resolved as module_only } from 'module-only'; | ||
export { resolved as module_require_import } from 'module-require-import'; | ||
export { resolved as require_module_import } from 'require-module-import'; |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
exports.require = require; |