Skip to content

Commit eb12158

Browse files
guybedfordRafaelGSS
authored andcommitted
esm: unflag import.meta.resolve
PR-URL: #49028 Reviewed-By: Geoffrey Booth <[email protected]> Reviewed-By: Jacob Smith <[email protected]> Reviewed-By: Mohammed Keyvanzadeh <[email protected]>
1 parent 1a6e945 commit eb12158

File tree

7 files changed

+57
-35
lines changed

7 files changed

+57
-35
lines changed

doc/api/cli.md

+10-1
Original file line numberDiff line numberDiff line change
@@ -512,9 +512,18 @@ of `--enable-source-maps`.
512512
added:
513513
- v13.9.0
514514
- 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.
515521
-->
516522

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.
518527

519528
### `--experimental-loader=module`
520529

doc/api/esm.md

+30-20
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,7 @@ import { readFileSync } from 'node:fs';
322322
const buffer = readFileSync(new URL('./data.proto', import.meta.url));
323323
```
324324
325-
### `import.meta.resolve(specifier[, parent])`
325+
### `import.meta.resolve(specifier)`
326326
327327
<!--
328328
added:
@@ -337,36 +337,45 @@ changes:
337337
- v14.18.0
338338
pr-url: https://github.com/nodejs/node/pull/38587
339339
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.
340345
-->
341346
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
346348
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.
351352
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.
358355
359356
```js
360357
const dependencyAsset = import.meta.resolve('component-lib/asset.css');
358+
// file:///app/node_modules/component-lib/asset.css
361359
```
362360
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.
365363
366364
```js
367365
import.meta.resolve('./dep', import.meta.url);
366+
// file:///app/dep
368367
```
369368
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+
370379
## Interoperability with CommonJS
371380
372381
### `import` statements
@@ -501,8 +510,8 @@ They can instead be loaded with [`module.createRequire()`][] or
501510
502511
Relative resolution can be handled via `new URL('./local', import.meta.url)`.
503512
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.
506515
507516
Alternatively `module.createRequire()` can be used.
508517
@@ -1698,7 +1707,7 @@ for ESM specifiers is [commonjs-extension-resolution-loader][].
16981707
[`data:` URLs]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs
16991708
[`export`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export
17001709
[`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
17021711
[`import.meta.url`]: #importmetaurl
17031712
[`import`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import
17041713
[`initialize`]: #initialize
@@ -1716,6 +1725,7 @@ for ESM specifiers is [commonjs-extension-resolution-loader][].
17161725
[cjs-module-lexer]: https://github.com/nodejs/cjs-module-lexer/tree/1.2.2
17171726
[commonjs-extension-resolution-loader]: https://github.com/nodejs/loaders-test/tree/main/commonjs-extension-resolution-loader
17181727
[custom https loader]: #https-loader
1728+
[import.meta.resolve]: #importmetaresolvespecifier
17191729
[load hook]: #loadurl-context-nextload
17201730
[percent-encoded]: url.md#percent-encoding-in-urls
17211731
[special scheme]: https://url.spec.whatwg.org/#special-scheme

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;

src/node_options.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -396,7 +396,7 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() {
396396
&EnvironmentOptions::experimental_wasm_modules,
397397
kAllowedInEnvvar);
398398
AddOption("--experimental-import-meta-resolve",
399-
"experimental ES Module import.meta.resolve() support",
399+
"experimental ES Module import.meta.resolve() parentURL support",
400400
&EnvironmentOptions::experimental_import_meta_resolve,
401401
kAllowedInEnvvar);
402402
AddOption("--experimental-permission",

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

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

4242
{
4343
const cp = spawn(execPath, [
44-
'--experimental-import-meta-resolve',
4544
'--input-type=module',
4645
'--eval', 'console.log(typeof import.meta.resolve)',
4746
]);
@@ -50,7 +49,6 @@ assert.strictEqual(import.meta.resolve('baz/', fixtures),
5049

5150
{
5251
const cp = spawn(execPath, [
53-
'--experimental-import-meta-resolve',
5452
'--input-type=module',
5553
]);
5654
cp.stdin.end('console.log(typeof import.meta.resolve)');
@@ -59,7 +57,6 @@ assert.strictEqual(import.meta.resolve('baz/', fixtures),
5957

6058
{
6159
const cp = spawn(execPath, [
62-
'--experimental-import-meta-resolve',
6360
'--input-type=module',
6461
'--eval', 'import "data:text/javascript,console.log(import.meta.resolve(%22node:os%22))"',
6562
]);
@@ -68,7 +65,6 @@ assert.strictEqual(import.meta.resolve('baz/', fixtures),
6865

6966
{
7067
const cp = spawn(execPath, [
71-
'--experimental-import-meta-resolve',
7268
'--input-type=module',
7369
]);
7470
cp.stdin.end('import "data:text/javascript,console.log(import.meta.resolve(%22node:os%22))"');

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);

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'),
@@ -207,7 +206,6 @@ describe('Loader hooks', { concurrency: true }, () => {
207206
it('should not leak internals or expose import.meta.resolve', async () => {
208207
const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
209208
'--no-warnings',
210-
'--experimental-import-meta-resolve',
211209
'--experimental-loader',
212210
fixtures.fileURL('es-module-loaders/loader-edge-cases.mjs'),
213211
fixtures.path('empty.js'),
@@ -222,7 +220,6 @@ describe('Loader hooks', { concurrency: true }, () => {
222220
it('should be fine to call `process.exit` from a custom async hook', async () => {
223221
const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
224222
'--no-warnings',
225-
'--experimental-import-meta-resolve',
226223
'--experimental-loader',
227224
'data:text/javascript,export function load(a,b,next){if(a==="data:exit")process.exit(42);return next(a,b)}',
228225
'--input-type=module',
@@ -239,7 +236,6 @@ describe('Loader hooks', { concurrency: true }, () => {
239236
it('should be fine to call `process.exit` from a custom sync hook', async () => {
240237
const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
241238
'--no-warnings',
242-
'--experimental-import-meta-resolve',
243239
'--experimental-loader',
244240
'data:text/javascript,export function resolve(a,b,next){if(a==="exit:")process.exit(42);return next(a,b)}',
245241
'--input-type=module',

0 commit comments

Comments
 (0)