Skip to content

Commit 56ecf29

Browse files
authored
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 e9ff810 commit 56ecf29

File tree

3 files changed

+46
-11
lines changed

3 files changed

+46
-11
lines changed

doc/api/module.md

Lines changed: 8 additions & 4 deletions
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

Lines changed: 7 additions & 7 deletions
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,
@@ -321,7 +321,7 @@ class ModuleLoader {
321321
// eslint-disable-next-line no-use-before-define
322322
this.setCustomizations(new CustomizedModuleLoader());
323323
}
324-
return this.#customizations.register(specifier, parentURL, data, transferList);
324+
return this.#customizations.register(`${specifier}`, `${parentURL}`, data, transferList);
325325
}
326326

327327
/**
@@ -542,11 +542,11 @@ function getHooksProxy() {
542542

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

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

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,37 @@ describe('Loader hooks', { concurrency: true }, () => {
517517
assert.strictEqual(signal, null);
518518
});
519519

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

0 commit comments

Comments
 (0)