Skip to content

Commit cdd52f5

Browse files
committed
esm: unflag import.meta.resolve
PR-URL: nodejs/node#49028 Backport-PR-URL: nodejs/node#50669 Reviewed-By: Geoffrey Booth <[email protected]> Reviewed-By: Jacob Smith <[email protected]> Reviewed-By: Mohammed Keyvanzadeh <[email protected]>
1 parent a6212a3 commit cdd52f5

File tree

7 files changed

+57
-35
lines changed

7 files changed

+57
-35
lines changed

graal-nodejs/doc/api/cli.md

+10-1
Original file line numberDiff line numberDiff line change
@@ -372,9 +372,18 @@ Expose the [Web Crypto API][] on the global scope.
372372
added:
373373
- v13.9.0
374374
- v12.16.2
375+
changes:
376+
- version: REPLACEME
377+
pr-url: https://github.com/nodejs/node/pull/49028
378+
description: synchronous import.meta.resolve made available by default, with
379+
the flag retained for enabling the experimental second argument
380+
as previously supported.
375381
-->
376382

377-
Enable experimental `import.meta.resolve()` support.
383+
Enable experimental `import.meta.resolve()` parent URL support, which allows
384+
passing a second `parentURL` argument for contextual resolution.
385+
386+
Previously gated the entire `import.meta.resolve` feature.
378387

379388
### `--experimental-loader=module`
380389

graal-nodejs/doc/api/esm.md

+30-20
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ import { readFileSync } from 'node:fs';
321321
const buffer = readFileSync(new URL('./data.proto', import.meta.url));
322322
```
323323
324-
### `import.meta.resolve(specifier[, parent])`
324+
### `import.meta.resolve(specifier)`
325325
326326
<!--
327327
added:
@@ -336,36 +336,45 @@ changes:
336336
- v14.18.0
337337
pr-url: https://github.com/nodejs/node/pull/38587
338338
description: Add support for WHATWG `URL` object to `parentURL` parameter.
339+
- version:
340+
- REPLACEME
341+
pr-url: https://github.com/nodejs/node/pull/49028
342+
description: Unflag import.meta.resolve, with `parentURL` parameter still
343+
flagged.
339344
-->
340345
341-
> Stability: 1 - Experimental
342-
343-
This feature is only available with the `--experimental-import-meta-resolve`
344-
command flag enabled.
346+
> Stability: 1.2 - Release candidate
345347
346-
* `specifier` {string} The module specifier to resolve relative to `parent`.
347-
* `parent` {string|URL} The absolute parent module URL to resolve from. If none
348-
is specified, the value of `import.meta.url` is used as the default.
349-
* Returns: {string}
348+
* `specifier` {string} The module specifier to resolve relative to the
349+
current module.
350+
* Returns: {string} The absolute (`file:`) URL string for the resolved module.
350351
351-
Provides a module-relative resolution function scoped to each module, returning
352-
the URL string. In alignment with browser behavior, this now returns
353-
synchronously.
354-
355-
> **Caveat** This can result in synchronous file-system operations, which
356-
> can impact performance similarly to `require.resolve`.
352+
[`import.meta.resolve`][] is a module-relative resolution function scoped to
353+
each module, returning the URL string.
357354
358355
```js
359356
const dependencyAsset = import.meta.resolve('component-lib/asset.css');
357+
// file:///app/node_modules/component-lib/asset.css
360358
```
361359
362-
`import.meta.resolve` also accepts a second argument which is the parent module
363-
from which to resolve:
360+
All features of the Node.js module resolution are supported. Dependency
361+
resolutions are subject to the permitted exports resolutions within the package.
364362
365363
```js
366364
import.meta.resolve('./dep', import.meta.url);
365+
// file:///app/dep
367366
```
368367
368+
> **Caveat** This can result in synchronous file-system operations, which
369+
> can impact performance similarly to `require.resolve`.
370+
371+
Previously, Node.js implemented an asynchronous resolver which also permitted
372+
a second contextual argument. The implementation has since been updated to be
373+
synchronous, with the second contextual `parent` argument still accessible
374+
behind the `--experimental-import-meta-resolve` flag:
375+
376+
* `parent` {string|URL} An optional absolute parent module URL to resolve from.
377+
369378
## Interoperability with CommonJS
370379
371380
### `import` statements
@@ -500,8 +509,8 @@ They can instead be loaded with [`module.createRequire()`][] or
500509
501510
Relative resolution can be handled via `new URL('./local', import.meta.url)`.
502511
503-
For a complete `require.resolve` replacement, there is a flagged experimental
504-
[`import.meta.resolve`][] API.
512+
For a complete `require.resolve` replacement, there is the
513+
[import.meta.resolve][] API.
505514
506515
Alternatively `module.createRequire()` can be used.
507516
@@ -1705,7 +1714,7 @@ success!
17051714
[`data:` URLs]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs
17061715
[`export`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export
17071716
[`import()`]: #import-expressions
1708-
[`import.meta.resolve`]: #importmetaresolvespecifier-parent
1717+
[`import.meta.resolve`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import.meta/resolve
17091718
[`import.meta.url`]: #importmetaurl
17101719
[`import`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import
17111720
[`initialize`]: #initialize
@@ -1722,6 +1731,7 @@ success!
17221731
[`util.TextDecoder`]: util.md#class-utiltextdecoder
17231732
[cjs-module-lexer]: https://github.com/nodejs/cjs-module-lexer/tree/1.2.2
17241733
[custom https loader]: #https-loader
1734+
[import.meta.resolve]: #importmetaresolvespecifier
17251735
[load hook]: #loadurl-context-nextload
17261736
[percent-encoded]: url.md#percent-encoding-in-urls
17271737
[special scheme]: https://url.spec.whatwg.org/#special-scheme

graal-nodejs/lib/internal/modules/esm/initialize_import_meta.js

+15-4
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,22 @@ const experimentalImportMetaResolve = getOptionValue('--experimental-import-meta
77
* Generate a function to be used as import.meta.resolve for a particular module.
88
* @param {string} defaultParentURL The default base to use for resolution
99
* @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
1112
*/
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+
*/
1319
return function resolve(specifier, parentURL = defaultParentURL) {
1420
let url;
21+
22+
if (!allowParentURL) {
23+
parentURL = defaultParentURL;
24+
}
25+
1526
try {
1627
({ url } = loader.resolveSync(specifier, parentURL));
1728
return url;
@@ -40,8 +51,8 @@ function initializeImportMeta(meta, context, loader) {
4051
const { url } = context;
4152

4253
// Alphabetical
43-
if (experimentalImportMetaResolve && loader.allowImportMetaResolve) {
44-
meta.resolve = createImportMetaResolve(url, loader);
54+
if (!loader || loader.allowImportMetaResolve) {
55+
meta.resolve = createImportMetaResolve(url, loader, experimentalImportMetaResolve);
4556
}
4657

4758
meta.url = url;

graal-nodejs/src/node_options.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -400,7 +400,7 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() {
400400
&EnvironmentOptions::experimental_wasm_modules,
401401
kAllowedInEnvvar);
402402
AddOption("--experimental-import-meta-resolve",
403-
"experimental ES Module import.meta.resolve() support",
403+
"experimental ES Module import.meta.resolve() parentURL support",
404404
&EnvironmentOptions::experimental_import_meta_resolve,
405405
kAllowedInEnvvar);
406406
AddOption("--experimental-policy",

graal-nodejs/test/es-module/test-esm-import-meta-resolve.mjs

-4
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ assert.strictEqual(import.meta.resolve('baz/', fixtures),
3939

4040
{
4141
const cp = spawn(execPath, [
42-
'--experimental-import-meta-resolve',
4342
'--input-type=module',
4443
'--eval', 'console.log(typeof import.meta.resolve)',
4544
]);
@@ -48,7 +47,6 @@ assert.strictEqual(import.meta.resolve('baz/', fixtures),
4847

4948
{
5049
const cp = spawn(execPath, [
51-
'--experimental-import-meta-resolve',
5250
'--input-type=module',
5351
]);
5452
cp.stdin.end('console.log(typeof import.meta.resolve)');
@@ -57,7 +55,6 @@ assert.strictEqual(import.meta.resolve('baz/', fixtures),
5755

5856
{
5957
const cp = spawn(execPath, [
60-
'--experimental-import-meta-resolve',
6158
'--input-type=module',
6259
'--eval', 'import "data:text/javascript,console.log(import.meta.resolve(%22node:os%22))"',
6360
]);
@@ -66,7 +63,6 @@ assert.strictEqual(import.meta.resolve('baz/', fixtures),
6663

6764
{
6865
const cp = spawn(execPath, [
69-
'--experimental-import-meta-resolve',
7066
'--input-type=module',
7167
]);
7268
cp.stdin.end('import "data:text/javascript,console.log(import.meta.resolve(%22node:os%22))"');

graal-nodejs/test/es-module/test-esm-import-meta.mjs

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import assert from 'assert';
33

44
assert.strictEqual(Object.getPrototypeOf(import.meta), null);
55

6-
const keys = ['url'];
6+
const keys = ['resolve', 'url'];
77
assert.deepStrictEqual(Reflect.ownKeys(import.meta), keys);
88

99
const descriptors = Object.getOwnPropertyDescriptors(import.meta);

graal-nodejs/test/es-module/test-esm-loader-hooks.mjs

-4
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,6 @@ describe('Loader hooks', { concurrency: true }, () => {
9494
it('import.meta.resolve of a never-settling resolve', async () => {
9595
const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
9696
'--no-warnings',
97-
'--experimental-import-meta-resolve',
9897
'--experimental-loader',
9998
fixtures.fileURL('es-module-loaders/never-settling-resolve-step/loader.mjs'),
10099
fixtures.path('es-module-loaders/never-settling-resolve-step/import.meta.never-resolve.mjs'),
@@ -155,7 +154,6 @@ describe('Loader hooks', { concurrency: true }, () => {
155154
it('should not leak internals or expose import.meta.resolve', async () => {
156155
const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
157156
'--no-warnings',
158-
'--experimental-import-meta-resolve',
159157
'--experimental-loader',
160158
fixtures.fileURL('es-module-loaders/loader-edge-cases.mjs'),
161159
fixtures.path('empty.js'),
@@ -170,7 +168,6 @@ describe('Loader hooks', { concurrency: true }, () => {
170168
it('should be fine to call `process.exit` from a custom async hook', async () => {
171169
const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
172170
'--no-warnings',
173-
'--experimental-import-meta-resolve',
174171
'--experimental-loader',
175172
'data:text/javascript,export function load(a,b,next){if(a==="data:exit")process.exit(42);return next(a,b)}',
176173
'--input-type=module',
@@ -187,7 +184,6 @@ describe('Loader hooks', { concurrency: true }, () => {
187184
it('should be fine to call `process.exit` from a custom sync hook', async () => {
188185
const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
189186
'--no-warnings',
190-
'--experimental-import-meta-resolve',
191187
'--experimental-loader',
192188
'data:text/javascript,export function resolve(a,b,next){if(a==="exit:")process.exit(42);return next(a,b)}',
193189
'--input-type=module',

0 commit comments

Comments
 (0)