GeezerVison is showing github.com — esm: unflag import.meta.resolve · nodejs/node@eb12158
File treeExpand file treeCollapse file tree Open diff view settings Expand file treeCollapse file tree Open diff view settings Collapse file Copy file name to clipboardExpand all lines: doc/api/cli.md +10-1Lines changed: 10 additions & 1 deletion - Display the source diff
- Display the rich diff
| Original file line number | Diff line number | Diff line change |
|---|
@@ -512,9 +512,18 @@ of `--enable-source-maps`. | 512 | 512 | added: | 513 | 513 | - v13.9.0 | 514 | 514 | - v12.16.2 | | 515 | +changes: | | 516 | + - version: REPLACEME | | 517 | + pr-url: https://github.com/nodejs/node/pull/49028 | | 518 | + description: synchronous import.meta.resolve made available by default, with | | 519 | + the flag retained for enabling the experimental second argument | | 520 | + as previously supported. | 515 | 521 | --> | 516 | 522 |
| 517 | | -Enable experimental `import.meta.resolve()` support. | | 523 | +Enable experimental `import.meta.resolve()` parent URL support, which allows | | 524 | +passing a second `parentURL` argument for contextual resolution. | | 525 | + | | 526 | +Previously gated the entire `import.meta.resolve` feature. | 518 | 527 |
| 519 | 528 | ### `--experimental-loader=module` | 520 | 529 |
| |
Collapse file Copy file name to clipboardExpand all lines: doc/api/esm.md +30-20Lines changed: 30 additions & 20 deletions - Display the source diff
- Display the rich diff
| Original file line number | Diff line number | Diff line change |
|---|
@@ -322,7 +322,7 @@ import { readFileSync } from 'node:fs'; | 322 | 322 | const buffer = readFileSync(new URL('./data.proto', import.meta.url)); | 323 | 323 | ``` | 324 | 324 |
| 325 | | -### `import.meta.resolve(specifier[, parent])` | | 325 | +### `import.meta.resolve(specifier)` | 326 | 326 |
| 327 | 327 | <!-- | 328 | 328 | added: | @@ -337,36 +337,45 @@ changes: | 337 | 337 | - v14.18.0 | 338 | 338 | pr-url: https://github.com/nodejs/node/pull/38587 | 339 | 339 | description: Add support for WHATWG `URL` object to `parentURL` parameter. | | 340 | + - version: | | 341 | + - REPLACEME | | 342 | + pr-url: https://github.com/nodejs/node/pull/49028 | | 343 | + description: Unflag import.meta.resolve, with `parentURL` parameter still | | 344 | + flagged. | 340 | 345 | --> | 341 | 346 |
| 342 | | -> Stability: 1 - Experimental | 343 | | -
| 344 | | -This feature is only available with the `--experimental-import-meta-resolve` | 345 | | -command flag enabled. | | 347 | +> Stability: 1.2 - Release candidate | 346 | 348 |
| 347 | | -* `specifier` {string} The module specifier to resolve relative to `parent`. | 348 | | -* `parent` {string|URL} The absolute parent module URL to resolve from. If none | 349 | | - is specified, the value of `import.meta.url` is used as the default. | 350 | | -* Returns: {string} | | 349 | +* `specifier` {string} The module specifier to resolve relative to the | | 350 | + current module. | | 351 | +* Returns: {string} The absolute (`file:`) URL string for the resolved module. | 351 | 352 |
| 352 | | -Provides a module-relative resolution function scoped to each module, returning | 353 | | -the URL string. In alignment with browser behavior, this now returns | 354 | | -synchronously. | 355 | | -
| 356 | | -> **Caveat** This can result in synchronous file-system operations, which | 357 | | -> can impact performance similarly to `require.resolve`. | | 353 | +[`import.meta.resolve`][] is a module-relative resolution function scoped to | | 354 | +each module, returning the URL string. | 358 | 355 |
| 359 | 356 | ```js | 360 | 357 | const dependencyAsset = import.meta.resolve('component-lib/asset.css'); | | 358 | +// file:///app/node_modules/component-lib/asset.css | 361 | 359 | ``` | 362 | 360 |
| 363 | | -`import.meta.resolve` also accepts a second argument which is the parent module | 364 | | -from which to resolve: | | 361 | +All features of the Node.js module resolution are supported. Dependency | | 362 | +resolutions are subject to the permitted exports resolutions within the package. | 365 | 363 |
| 366 | 364 | ```js | 367 | 365 | import.meta.resolve('./dep', import.meta.url); | | 366 | +// file:///app/dep | 368 | 367 | ``` | 369 | 368 |
| | 369 | +> **Caveat** This can result in synchronous file-system operations, which | | 370 | +> can impact performance similarly to `require.resolve`. | | 371 | +
| | 372 | +Previously, Node.js implemented an asynchronous resolver which also permitted | | 373 | +a second contextual argument. The implementation has since been updated to be | | 374 | +synchronous, with the second contextual `parent` argument still accessible | | 375 | +behind the `--experimental-import-meta-resolve` flag: | | 376 | +
| | 377 | +* `parent` {string|URL} An optional absolute parent module URL to resolve from. | | 378 | +
| 370 | 379 | ## Interoperability with CommonJS | 371 | 380 |
| 372 | 381 | ### `import` statements | @@ -501,8 +510,8 @@ They can instead be loaded with [`module.createRequire()`][] or | 501 | 510 |
| 502 | 511 | Relative resolution can be handled via `new URL('./local', import.meta.url)`. | 503 | 512 |
| 504 | | -For a complete `require.resolve` replacement, there is a flagged experimental | 505 | | -[`import.meta.resolve`][] API. | | 513 | +For a complete `require.resolve` replacement, there is the | | 514 | +[import.meta.resolve][] API. | 506 | 515 |
| 507 | 516 | Alternatively `module.createRequire()` can be used. | 508 | 517 |
| @@ -1698,7 +1707,7 @@ for ESM specifiers is [commonjs-extension-resolution-loader][]. | 1698 | 1707 | [`data:` URLs]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs | 1699 | 1708 | [`export`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export | 1700 | 1709 | [`import()`]: #import-expressions | 1701 | | -[`import.meta.resolve`]: #importmetaresolvespecifier-parent | | 1710 | +[`import.meta.resolve`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import.meta/resolve | 1702 | 1711 | [`import.meta.url`]: #importmetaurl | 1703 | 1712 | [`import`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import | 1704 | 1713 | [`initialize`]: #initialize | @@ -1716,6 +1725,7 @@ for ESM specifiers is [commonjs-extension-resolution-loader][]. | 1716 | 1725 | [cjs-module-lexer]: https://github.com/nodejs/cjs-module-lexer/tree/1.2.2 | 1717 | 1726 | [commonjs-extension-resolution-loader]: https://github.com/nodejs/loaders-test/tree/main/commonjs-extension-resolution-loader | 1718 | 1727 | [custom https loader]: #https-loader | | 1728 | +[import.meta.resolve]: #importmetaresolvespecifier | 1719 | 1729 | [load hook]: #loadurl-context-nextload | 1720 | 1730 | [percent-encoded]: url.md#percent-encoding-in-urls | 1721 | 1731 | [special scheme]: https://url.spec.whatwg.org/#special-scheme | |
Collapse file Copy file name to clipboardExpand all lines: lib/internal/modules/esm/initialize_import_meta.js +15-4Lines changed: 15 additions & 4 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -7,11 +7,22 @@ const experimentalImportMetaResolve = getOptionValue('--experimental-import-meta | 7 | 7 | * Generate a function to be used as import.meta.resolve for a particular module. | 8 | 8 | * @param {string} defaultParentURL The default base to use for resolution | 9 | 9 | * @param {typeof import('./loader.js').ModuleLoader} loader Reference to the current module loader | 10 | | - * @returns {(specifier: string, parentURL?: string) => string} Function to assign to import.meta.resolve | | 10 | + * @param {bool} allowParentURL Whether to permit parentURL second argument for contextual resolution | | 11 | + * @returns {(specifier: string) => string} Function to assign to import.meta.resolve | 11 | 12 | */ | 12 | | -function createImportMetaResolve(defaultParentURL, loader) { | | 13 | +function createImportMetaResolve(defaultParentURL, loader, allowParentURL) { | | 14 | + /** | | 15 | + * @param {string} specifier | | 16 | + * @param {URL['href']} [parentURL] When `--experimental-import-meta-resolve` is specified, a | | 17 | + * second argument can be provided. | | 18 | + */ | 13 | 19 | return function resolve(specifier, parentURL = defaultParentURL) { | 14 | 20 | let url; | | 21 | + | | 22 | + if (!allowParentURL) { | | 23 | + parentURL = defaultParentURL; | | 24 | + } | | 25 | + | 15 | 26 | try { | 16 | 27 | ({ url } = loader.resolveSync(specifier, parentURL)); | 17 | 28 | return url; | @@ -40,8 +51,8 @@ function initializeImportMeta(meta, context, loader) { | 40 | 51 | const { url } = context; | 41 | 52 |
| 42 | 53 | // Alphabetical | 43 | | - if (experimentalImportMetaResolve && loader.allowImportMetaResolve) { | 44 | | - meta.resolve = createImportMetaResolve(url, loader); | | 54 | + if (!loader || loader.allowImportMetaResolve) { | | 55 | + meta.resolve = createImportMetaResolve(url, loader, experimentalImportMetaResolve); | 45 | 56 | } | 46 | 57 |
| 47 | 58 | meta.url = url; | |
Collapse file Copy file name to clipboardExpand all lines: src/node_options.cc +1-1Lines changed: 1 addition & 1 deletion | Original file line number | Diff line number | Diff line change |
|---|
@@ -396,7 +396,7 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() { | 396 | 396 | &EnvironmentOptions::experimental_wasm_modules, | 397 | 397 | kAllowedInEnvvar); | 398 | 398 | AddOption("--experimental-import-meta-resolve", | 399 | | - "experimental ES Module import.meta.resolve() support", | | 399 | + "experimental ES Module import.meta.resolve() parentURL support", | 400 | 400 | &EnvironmentOptions::experimental_import_meta_resolve, | 401 | 401 | kAllowedInEnvvar); | 402 | 402 | AddOption("--experimental-permission", | |
Collapse file Copy file name to clipboardExpand all lines: test/es-module/test-esm-import-meta-resolve.mjs -4Lines changed: 0 additions & 4 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -41,7 +41,6 @@ assert.strictEqual(import.meta.resolve('baz/', fixtures), | 41 | 41 |
| 42 | 42 | { | 43 | 43 | const cp = spawn(execPath, [ | 44 | | - '--experimental-import-meta-resolve', | 45 | 44 | '--input-type=module', | 46 | 45 | '--eval', 'console.log(typeof import.meta.resolve)', | 47 | 46 | ]); | @@ -50,7 +49,6 @@ assert.strictEqual(import.meta.resolve('baz/', fixtures), | 50 | 49 |
| 51 | 50 | { | 52 | 51 | const cp = spawn(execPath, [ | 53 | | - '--experimental-import-meta-resolve', | 54 | 52 | '--input-type=module', | 55 | 53 | ]); | 56 | 54 | cp.stdin.end('console.log(typeof import.meta.resolve)'); | @@ -59,7 +57,6 @@ assert.strictEqual(import.meta.resolve('baz/', fixtures), | 59 | 57 |
| 60 | 58 | { | 61 | 59 | const cp = spawn(execPath, [ | 62 | | - '--experimental-import-meta-resolve', | 63 | 60 | '--input-type=module', | 64 | 61 | '--eval', 'import "data:text/javascript,console.log(import.meta.resolve(%22node:os%22))"', | 65 | 62 | ]); | @@ -68,7 +65,6 @@ assert.strictEqual(import.meta.resolve('baz/', fixtures), | 68 | 65 |
| 69 | 66 | { | 70 | 67 | const cp = spawn(execPath, [ | 71 | | - '--experimental-import-meta-resolve', | 72 | 68 | '--input-type=module', | 73 | 69 | ]); | 74 | 70 | cp.stdin.end('import "data:text/javascript,console.log(import.meta.resolve(%22node:os%22))"'); | |
Collapse file Copy file name to clipboardExpand all lines: test/es-module/test-esm-import-meta.mjs +1-1Lines changed: 1 addition & 1 deletion | Original file line number | Diff line number | Diff line change |
|---|
@@ -3,7 +3,7 @@ import assert from 'assert'; | 3 | 3 |
| 4 | 4 | assert.strictEqual(Object.getPrototypeOf(import.meta), null); | 5 | 5 |
| 6 | | -const keys = ['url']; | | 6 | +const keys = ['resolve', 'url']; | 7 | 7 | assert.deepStrictEqual(Reflect.ownKeys(import.meta), keys); | 8 | 8 |
| 9 | 9 | const descriptors = Object.getOwnPropertyDescriptors(import.meta); | |
Collapse file Copy file name to clipboardExpand all lines: test/es-module/test-esm-loader-hooks.mjs -4Lines changed: 0 additions & 4 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -94,7 +94,6 @@ describe('Loader hooks', { concurrency: true }, () => { | 94 | 94 | it('import.meta.resolve of a never-settling resolve', async () => { | 95 | 95 | const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [ | 96 | 96 | '--no-warnings', | 97 | | - '--experimental-import-meta-resolve', | 98 | 97 | '--experimental-loader', | 99 | 98 | fixtures.fileURL('es-module-loaders/never-settling-resolve-step/loader.mjs'), | 100 | 99 | fixtures.path('es-module-loaders/never-settling-resolve-step/import.meta.never-resolve.mjs'), | @@ -207,7 +206,6 @@ describe('Loader hooks', { concurrency: true }, () => { | 207 | 206 | it('should not leak internals or expose import.meta.resolve', async () => { | 208 | 207 | const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [ | 209 | 208 | '--no-warnings', | 210 | | - '--experimental-import-meta-resolve', | 211 | 209 | '--experimental-loader', | 212 | 210 | fixtures.fileURL('es-module-loaders/loader-edge-cases.mjs'), | 213 | 211 | fixtures.path('empty.js'), | @@ -222,7 +220,6 @@ describe('Loader hooks', { concurrency: true }, () => { | 222 | 220 | it('should be fine to call `process.exit` from a custom async hook', async () => { | 223 | 221 | const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [ | 224 | 222 | '--no-warnings', | 225 | | - '--experimental-import-meta-resolve', | 226 | 223 | '--experimental-loader', | 227 | 224 | 'data:text/javascript,export function load(a,b,next){if(a==="data:exit")process.exit(42);return next(a,b)}', | 228 | 225 | '--input-type=module', | @@ -239,7 +236,6 @@ describe('Loader hooks', { concurrency: true }, () => { | 239 | 236 | it('should be fine to call `process.exit` from a custom sync hook', async () => { | 240 | 237 | const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [ | 241 | 238 | '--no-warnings', | 242 | | - '--experimental-import-meta-resolve', | 243 | 239 | '--experimental-loader', | 244 | 240 | 'data:text/javascript,export function resolve(a,b,next){if(a==="exit:")process.exit(42);return next(a,b)}', | 245 | 241 | '--input-type=module', | |
|