Skip to content

Commit 521a932

Browse files
aduh95ruyadorno
authored andcommitted
esm: fix support for URL instances in register
PR-URL: #49655 Reviewed-By: Geoffrey Booth <[email protected]> Reviewed-By: Yagiz Nizipli <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent 7b6a731 commit 521a932

File tree

3 files changed

+46
-11
lines changed

3 files changed

+46
-11
lines changed

doc/api/module.md

+8-4
Original file line numberDiff line numberDiff line change
@@ -84,14 +84,18 @@ isBuiltin('wss'); // false
8484
8585
<!-- YAML
8686
added: v20.6.0
87+
changes:
88+
- version: REPLACEME
89+
pr-url: https://github.com/nodejs/node/pull/49655
90+
description: Add support for WHATWG URL instances.
8791
-->
8892
8993
> Stability: 1.2 - Release candidate
9094
91-
* `specifier` {string} Customization hooks to be registered; this should be the
92-
same string that would be passed to `import()`, except that if it is relative,
93-
it is resolved relative to `parentURL`.
94-
* `parentURL` {string} If you want to resolve `specifier` relative to a base
95+
* `specifier` {string|URL} Customization hooks to be registered; this should be
96+
the same string that would be passed to `import()`, except that if it is
97+
relative, it is resolved relative to `parentURL`.
98+
* `parentURL` {string|URL} If you want to resolve `specifier` relative to a base
9599
URL, such as `import.meta.url`, you can pass that URL here. **Default:**
96100
`'data:'`
97101
* `options` {Object}

lib/internal/modules/esm/loader.js

+7-7
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ const {
1414
ERR_UNKNOWN_MODULE_FORMAT,
1515
} = require('internal/errors').codes;
1616
const { getOptionValue } = require('internal/options');
17-
const { pathToFileURL } = require('internal/url');
17+
const { pathToFileURL, isURL } = require('internal/url');
1818
const { emitExperimentalWarning } = require('internal/util');
1919
const {
2020
getDefaultConditions,
@@ -320,7 +320,7 @@ class ModuleLoader {
320320
// eslint-disable-next-line no-use-before-define
321321
this.setCustomizations(new CustomizedModuleLoader());
322322
}
323-
return this.#customizations.register(specifier, parentURL, data, transferList);
323+
return this.#customizations.register(`${specifier}`, `${parentURL}`, data, transferList);
324324
}
325325

326326
/**
@@ -541,11 +541,11 @@ function getHooksProxy() {
541541

542542
/**
543543
* Register a single loader programmatically.
544-
* @param {string} specifier
545-
* @param {string} [parentURL] Base to use when resolving `specifier`; optional if
544+
* @param {string|import('url').URL} specifier
545+
* @param {string|import('url').URL} [parentURL] Base to use when resolving `specifier`; optional if
546546
* `specifier` is absolute. Same as `options.parentUrl`, just inline
547547
* @param {object} [options] Additional options to apply, described below.
548-
* @param {string} [options.parentURL] Base to use when resolving `specifier`
548+
* @param {string|import('url').URL} [options.parentURL] Base to use when resolving `specifier`
549549
* @param {any} [options.data] Arbitrary data passed to the loader's `initialize` hook
550550
* @param {any[]} [options.transferList] Objects in `data` that are changing ownership
551551
* @returns {void} We want to reserve the return value for potential future extension of the API.
@@ -570,12 +570,12 @@ function getHooksProxy() {
570570
*/
571571
function register(specifier, parentURL = undefined, options) {
572572
const moduleLoader = require('internal/process/esm_loader').esmLoader;
573-
if (parentURL != null && typeof parentURL === 'object') {
573+
if (parentURL != null && typeof parentURL === 'object' && !isURL(parentURL)) {
574574
options = parentURL;
575575
parentURL = options.parentURL;
576576
}
577577
moduleLoader.register(
578-
`${specifier}`,
578+
specifier,
579579
parentURL ?? 'data:',
580580
options?.data,
581581
options?.transferList,

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

+31
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,37 @@ describe('Loader hooks', { concurrency: true }, () => {
507507
assert.strictEqual(signal, null);
508508
});
509509

510+
it('should have `register` accept URL objects as `parentURL`', async () => {
511+
const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
512+
'--no-warnings',
513+
'--import',
514+
`data:text/javascript,${encodeURIComponent(
515+
'import{ register } from "node:module";' +
516+
'import { pathToFileURL } from "node:url";' +
517+
'register("./hooks-initialize.mjs", pathToFileURL("./"));'
518+
)}`,
519+
'--input-type=module',
520+
'--eval',
521+
`
522+
import {register} from 'node:module';
523+
register(
524+
${JSON.stringify(fixtures.fileURL('es-module-loaders/loader-load-foo-or-42.mjs'))},
525+
new URL('data:'),
526+
);
527+
528+
import('node:os').then((result) => {
529+
console.log(JSON.stringify(result));
530+
});
531+
`,
532+
], { cwd: fixtures.fileURL('es-module-loaders/') });
533+
534+
assert.strictEqual(stderr, '');
535+
assert.deepStrictEqual(stdout.split('\n').sort(), ['hooks initialize 1', '{"default":"foo"}', ''].sort());
536+
537+
assert.strictEqual(code, 0);
538+
assert.strictEqual(signal, null);
539+
});
540+
510541
it('should have `register` work with cjs', async () => {
511542
const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
512543
'--no-warnings',

0 commit comments

Comments
 (0)