esm: unflag import.meta.resolve
PR-URL: https://github.com/nodejs/node/pull/49028 Reviewed-By: Geoffrey Booth <webadmin@geoffreybooth.com> Reviewed-By: Jacob Smith <jacob@frende.me> Reviewed-By: Mohammed Keyvanzadeh <mohammadkeyvanzade94@gmail.com>
This commit is contained in:
parent
3d20582c0f
commit
ee8b7f1f18
@ -512,9 +512,18 @@ of `--enable-source-maps`.
|
|||||||
added:
|
added:
|
||||||
- v13.9.0
|
- v13.9.0
|
||||||
- v12.16.2
|
- v12.16.2
|
||||||
|
changes:
|
||||||
|
- version: REPLACEME
|
||||||
|
pr-url: https://github.com/nodejs/node/pull/49028
|
||||||
|
description: synchronous import.meta.resolve made available by default, with
|
||||||
|
the flag retained for enabling the experimental second argument
|
||||||
|
as previously supported.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
Enable experimental `import.meta.resolve()` support.
|
Enable experimental `import.meta.resolve()` parent URL support, which allows
|
||||||
|
passing a second `parentURL` argument for contextual resolution.
|
||||||
|
|
||||||
|
Previously gated the entire `import.meta.resolve` feature.
|
||||||
|
|
||||||
### `--experimental-loader=module`
|
### `--experimental-loader=module`
|
||||||
|
|
||||||
|
@ -322,7 +322,7 @@ import { readFileSync } from 'node:fs';
|
|||||||
const buffer = readFileSync(new URL('./data.proto', import.meta.url));
|
const buffer = readFileSync(new URL('./data.proto', import.meta.url));
|
||||||
```
|
```
|
||||||
|
|
||||||
### `import.meta.resolve(specifier[, parent])`
|
### `import.meta.resolve(specifier)`
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
added:
|
added:
|
||||||
@ -337,35 +337,44 @@ changes:
|
|||||||
- v14.18.0
|
- v14.18.0
|
||||||
pr-url: https://github.com/nodejs/node/pull/38587
|
pr-url: https://github.com/nodejs/node/pull/38587
|
||||||
description: Add support for WHATWG `URL` object to `parentURL` parameter.
|
description: Add support for WHATWG `URL` object to `parentURL` parameter.
|
||||||
|
- version:
|
||||||
|
- REPLACEME
|
||||||
|
pr-url: https://github.com/nodejs/node/pull/49028
|
||||||
|
description: Unflag import.meta.resolve, with `parentURL` parameter still
|
||||||
|
flagged.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
> Stability: 1 - Experimental
|
> Stability: 1.2 - Release candidate
|
||||||
|
|
||||||
This feature is only available with the `--experimental-import-meta-resolve`
|
* `specifier` {string} The module specifier to resolve relative to the
|
||||||
command flag enabled.
|
current module.
|
||||||
|
* Returns: {string} The absolute (`file:`) URL string for the resolved module.
|
||||||
|
|
||||||
* `specifier` {string} The module specifier to resolve relative to `parent`.
|
[`import.meta.resolve`][] is a module-relative resolution function scoped to
|
||||||
* `parent` {string|URL} The absolute parent module URL to resolve from. If none
|
each module, returning the URL string.
|
||||||
is specified, the value of `import.meta.url` is used as the default.
|
|
||||||
* Returns: {string}
|
|
||||||
|
|
||||||
Provides a module-relative resolution function scoped to each module, returning
|
```js
|
||||||
the URL string. In alignment with browser behavior, this now returns
|
const dependencyAsset = import.meta.resolve('component-lib/asset.css');
|
||||||
synchronously.
|
// file:///app/node_modules/component-lib/asset.css
|
||||||
|
```
|
||||||
|
|
||||||
|
All features of the Node.js module resolution are supported. Dependency
|
||||||
|
resolutions are subject to the permitted exports resolutions within the package.
|
||||||
|
|
||||||
|
```js
|
||||||
|
import.meta.resolve('./dep', import.meta.url);
|
||||||
|
// file:///app/dep
|
||||||
|
```
|
||||||
|
|
||||||
> **Caveat** This can result in synchronous file-system operations, which
|
> **Caveat** This can result in synchronous file-system operations, which
|
||||||
> can impact performance similarly to `require.resolve`.
|
> can impact performance similarly to `require.resolve`.
|
||||||
|
|
||||||
```js
|
Previously, Node.js implemented an asynchronous resolver which also permitted
|
||||||
const dependencyAsset = import.meta.resolve('component-lib/asset.css');
|
a second contextual argument. The implementation has since been updated to be
|
||||||
```
|
synchronous, with the second contextual `parent` argument still accessible
|
||||||
|
behind the `--experimental-import-meta-resolve` flag:
|
||||||
|
|
||||||
`import.meta.resolve` also accepts a second argument which is the parent module
|
* `parent` {string|URL} An optional absolute parent module URL to resolve from.
|
||||||
from which to resolve:
|
|
||||||
|
|
||||||
```js
|
|
||||||
import.meta.resolve('./dep', import.meta.url);
|
|
||||||
```
|
|
||||||
|
|
||||||
## Interoperability with CommonJS
|
## Interoperability with CommonJS
|
||||||
|
|
||||||
@ -501,8 +510,8 @@ They can instead be loaded with [`module.createRequire()`][] or
|
|||||||
|
|
||||||
Relative resolution can be handled via `new URL('./local', import.meta.url)`.
|
Relative resolution can be handled via `new URL('./local', import.meta.url)`.
|
||||||
|
|
||||||
For a complete `require.resolve` replacement, there is a flagged experimental
|
For a complete `require.resolve` replacement, there is the
|
||||||
[`import.meta.resolve`][] API.
|
[import.meta.resolve][] API.
|
||||||
|
|
||||||
Alternatively `module.createRequire()` can be used.
|
Alternatively `module.createRequire()` can be used.
|
||||||
|
|
||||||
@ -1698,7 +1707,7 @@ for ESM specifiers is [commonjs-extension-resolution-loader][].
|
|||||||
[`data:` URLs]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs
|
[`data:` URLs]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs
|
||||||
[`export`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export
|
[`export`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export
|
||||||
[`import()`]: #import-expressions
|
[`import()`]: #import-expressions
|
||||||
[`import.meta.resolve`]: #importmetaresolvespecifier-parent
|
[`import.meta.resolve`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import.meta/resolve
|
||||||
[`import.meta.url`]: #importmetaurl
|
[`import.meta.url`]: #importmetaurl
|
||||||
[`import`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import
|
[`import`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import
|
||||||
[`initialize`]: #initialize
|
[`initialize`]: #initialize
|
||||||
@ -1716,6 +1725,7 @@ for ESM specifiers is [commonjs-extension-resolution-loader][].
|
|||||||
[cjs-module-lexer]: https://github.com/nodejs/cjs-module-lexer/tree/1.2.2
|
[cjs-module-lexer]: https://github.com/nodejs/cjs-module-lexer/tree/1.2.2
|
||||||
[commonjs-extension-resolution-loader]: https://github.com/nodejs/loaders-test/tree/main/commonjs-extension-resolution-loader
|
[commonjs-extension-resolution-loader]: https://github.com/nodejs/loaders-test/tree/main/commonjs-extension-resolution-loader
|
||||||
[custom https loader]: #https-loader
|
[custom https loader]: #https-loader
|
||||||
|
[import.meta.resolve]: #importmetaresolvespecifier
|
||||||
[load hook]: #loadurl-context-nextload
|
[load hook]: #loadurl-context-nextload
|
||||||
[percent-encoded]: url.md#percent-encoding-in-urls
|
[percent-encoded]: url.md#percent-encoding-in-urls
|
||||||
[special scheme]: https://url.spec.whatwg.org/#special-scheme
|
[special scheme]: https://url.spec.whatwg.org/#special-scheme
|
||||||
|
@ -7,11 +7,22 @@ const experimentalImportMetaResolve = getOptionValue('--experimental-import-meta
|
|||||||
* Generate a function to be used as import.meta.resolve for a particular module.
|
* Generate a function to be used as import.meta.resolve for a particular module.
|
||||||
* @param {string} defaultParentURL The default base to use for resolution
|
* @param {string} defaultParentURL The default base to use for resolution
|
||||||
* @param {typeof import('./loader.js').ModuleLoader} loader Reference to the current module loader
|
* @param {typeof import('./loader.js').ModuleLoader} loader Reference to the current module loader
|
||||||
* @returns {(specifier: string, parentURL?: string) => string} Function to assign to import.meta.resolve
|
* @param {bool} allowParentURL Whether to permit parentURL second argument for contextual resolution
|
||||||
|
* @returns {(specifier: string) => string} Function to assign to import.meta.resolve
|
||||||
|
*/
|
||||||
|
function createImportMetaResolve(defaultParentURL, loader, allowParentURL) {
|
||||||
|
/**
|
||||||
|
* @param {string} specifier
|
||||||
|
* @param {URL['href']} [parentURL] When `--experimental-import-meta-resolve` is specified, a
|
||||||
|
* second argument can be provided.
|
||||||
*/
|
*/
|
||||||
function createImportMetaResolve(defaultParentURL, loader) {
|
|
||||||
return function resolve(specifier, parentURL = defaultParentURL) {
|
return function resolve(specifier, parentURL = defaultParentURL) {
|
||||||
let url;
|
let url;
|
||||||
|
|
||||||
|
if (!allowParentURL) {
|
||||||
|
parentURL = defaultParentURL;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
({ url } = loader.resolveSync(specifier, parentURL));
|
({ url } = loader.resolveSync(specifier, parentURL));
|
||||||
return url;
|
return url;
|
||||||
@ -40,8 +51,8 @@ function initializeImportMeta(meta, context, loader) {
|
|||||||
const { url } = context;
|
const { url } = context;
|
||||||
|
|
||||||
// Alphabetical
|
// Alphabetical
|
||||||
if (experimentalImportMetaResolve && loader.allowImportMetaResolve) {
|
if (!loader || loader.allowImportMetaResolve) {
|
||||||
meta.resolve = createImportMetaResolve(url, loader);
|
meta.resolve = createImportMetaResolve(url, loader, experimentalImportMetaResolve);
|
||||||
}
|
}
|
||||||
|
|
||||||
meta.url = url;
|
meta.url = url;
|
||||||
|
@ -396,7 +396,7 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() {
|
|||||||
&EnvironmentOptions::experimental_wasm_modules,
|
&EnvironmentOptions::experimental_wasm_modules,
|
||||||
kAllowedInEnvvar);
|
kAllowedInEnvvar);
|
||||||
AddOption("--experimental-import-meta-resolve",
|
AddOption("--experimental-import-meta-resolve",
|
||||||
"experimental ES Module import.meta.resolve() support",
|
"experimental ES Module import.meta.resolve() parentURL support",
|
||||||
&EnvironmentOptions::experimental_import_meta_resolve,
|
&EnvironmentOptions::experimental_import_meta_resolve,
|
||||||
kAllowedInEnvvar);
|
kAllowedInEnvvar);
|
||||||
AddOption("--experimental-permission",
|
AddOption("--experimental-permission",
|
||||||
|
@ -41,7 +41,6 @@ assert.strictEqual(import.meta.resolve('baz/', fixtures),
|
|||||||
|
|
||||||
{
|
{
|
||||||
const cp = spawn(execPath, [
|
const cp = spawn(execPath, [
|
||||||
'--experimental-import-meta-resolve',
|
|
||||||
'--input-type=module',
|
'--input-type=module',
|
||||||
'--eval', 'console.log(typeof import.meta.resolve)',
|
'--eval', 'console.log(typeof import.meta.resolve)',
|
||||||
]);
|
]);
|
||||||
@ -50,7 +49,6 @@ assert.strictEqual(import.meta.resolve('baz/', fixtures),
|
|||||||
|
|
||||||
{
|
{
|
||||||
const cp = spawn(execPath, [
|
const cp = spawn(execPath, [
|
||||||
'--experimental-import-meta-resolve',
|
|
||||||
'--input-type=module',
|
'--input-type=module',
|
||||||
]);
|
]);
|
||||||
cp.stdin.end('console.log(typeof import.meta.resolve)');
|
cp.stdin.end('console.log(typeof import.meta.resolve)');
|
||||||
@ -59,7 +57,6 @@ assert.strictEqual(import.meta.resolve('baz/', fixtures),
|
|||||||
|
|
||||||
{
|
{
|
||||||
const cp = spawn(execPath, [
|
const cp = spawn(execPath, [
|
||||||
'--experimental-import-meta-resolve',
|
|
||||||
'--input-type=module',
|
'--input-type=module',
|
||||||
'--eval', 'import "data:text/javascript,console.log(import.meta.resolve(%22node:os%22))"',
|
'--eval', 'import "data:text/javascript,console.log(import.meta.resolve(%22node:os%22))"',
|
||||||
]);
|
]);
|
||||||
@ -68,7 +65,6 @@ assert.strictEqual(import.meta.resolve('baz/', fixtures),
|
|||||||
|
|
||||||
{
|
{
|
||||||
const cp = spawn(execPath, [
|
const cp = spawn(execPath, [
|
||||||
'--experimental-import-meta-resolve',
|
|
||||||
'--input-type=module',
|
'--input-type=module',
|
||||||
]);
|
]);
|
||||||
cp.stdin.end('import "data:text/javascript,console.log(import.meta.resolve(%22node:os%22))"');
|
cp.stdin.end('import "data:text/javascript,console.log(import.meta.resolve(%22node:os%22))"');
|
||||||
|
@ -3,7 +3,7 @@ import assert from 'assert';
|
|||||||
|
|
||||||
assert.strictEqual(Object.getPrototypeOf(import.meta), null);
|
assert.strictEqual(Object.getPrototypeOf(import.meta), null);
|
||||||
|
|
||||||
const keys = ['url'];
|
const keys = ['resolve', 'url'];
|
||||||
assert.deepStrictEqual(Reflect.ownKeys(import.meta), keys);
|
assert.deepStrictEqual(Reflect.ownKeys(import.meta), keys);
|
||||||
|
|
||||||
const descriptors = Object.getOwnPropertyDescriptors(import.meta);
|
const descriptors = Object.getOwnPropertyDescriptors(import.meta);
|
||||||
|
@ -94,7 +94,6 @@ describe('Loader hooks', { concurrency: true }, () => {
|
|||||||
it('import.meta.resolve of a never-settling resolve', async () => {
|
it('import.meta.resolve of a never-settling resolve', async () => {
|
||||||
const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
|
const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
|
||||||
'--no-warnings',
|
'--no-warnings',
|
||||||
'--experimental-import-meta-resolve',
|
|
||||||
'--experimental-loader',
|
'--experimental-loader',
|
||||||
fixtures.fileURL('es-module-loaders/never-settling-resolve-step/loader.mjs'),
|
fixtures.fileURL('es-module-loaders/never-settling-resolve-step/loader.mjs'),
|
||||||
fixtures.path('es-module-loaders/never-settling-resolve-step/import.meta.never-resolve.mjs'),
|
fixtures.path('es-module-loaders/never-settling-resolve-step/import.meta.never-resolve.mjs'),
|
||||||
@ -207,7 +206,6 @@ describe('Loader hooks', { concurrency: true }, () => {
|
|||||||
it('should not leak internals or expose import.meta.resolve', async () => {
|
it('should not leak internals or expose import.meta.resolve', async () => {
|
||||||
const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
|
const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
|
||||||
'--no-warnings',
|
'--no-warnings',
|
||||||
'--experimental-import-meta-resolve',
|
|
||||||
'--experimental-loader',
|
'--experimental-loader',
|
||||||
fixtures.fileURL('es-module-loaders/loader-edge-cases.mjs'),
|
fixtures.fileURL('es-module-loaders/loader-edge-cases.mjs'),
|
||||||
fixtures.path('empty.js'),
|
fixtures.path('empty.js'),
|
||||||
@ -222,7 +220,6 @@ describe('Loader hooks', { concurrency: true }, () => {
|
|||||||
it('should be fine to call `process.exit` from a custom async hook', async () => {
|
it('should be fine to call `process.exit` from a custom async hook', async () => {
|
||||||
const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
|
const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
|
||||||
'--no-warnings',
|
'--no-warnings',
|
||||||
'--experimental-import-meta-resolve',
|
|
||||||
'--experimental-loader',
|
'--experimental-loader',
|
||||||
'data:text/javascript,export function load(a,b,next){if(a==="data:exit")process.exit(42);return next(a,b)}',
|
'data:text/javascript,export function load(a,b,next){if(a==="data:exit")process.exit(42);return next(a,b)}',
|
||||||
'--input-type=module',
|
'--input-type=module',
|
||||||
@ -239,7 +236,6 @@ describe('Loader hooks', { concurrency: true }, () => {
|
|||||||
it('should be fine to call `process.exit` from a custom sync hook', async () => {
|
it('should be fine to call `process.exit` from a custom sync hook', async () => {
|
||||||
const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
|
const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
|
||||||
'--no-warnings',
|
'--no-warnings',
|
||||||
'--experimental-import-meta-resolve',
|
|
||||||
'--experimental-loader',
|
'--experimental-loader',
|
||||||
'data:text/javascript,export function resolve(a,b,next){if(a==="exit:")process.exit(42);return next(a,b)}',
|
'data:text/javascript,export function resolve(a,b,next){if(a==="exit:")process.exit(42);return next(a,b)}',
|
||||||
'--input-type=module',
|
'--input-type=module',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user