diff --git a/lib/internal/modules/esm/hooks.js b/lib/internal/modules/esm/hooks.js index cef2897bd68967..8f212ec8b1a3ba 100644 --- a/lib/internal/modules/esm/hooks.js +++ b/lib/internal/modules/esm/hooks.js @@ -124,7 +124,11 @@ class Hooks { * @param {string} urlOrSpecifier * @param {string} parentURL */ - async register(urlOrSpecifier, parentURL) { + async register(urlOrSpecifier, options) { + const { + parentURL = 'data:', + data, + } = options; const moduleLoader = require('internal/process/esm_loader').esmLoader; const keyedExports = await moduleLoader.import( @@ -133,7 +137,7 @@ class Hooks { kEmptyObject, ); - this.addCustomLoader(urlOrSpecifier, keyedExports); + this.addCustomLoader(urlOrSpecifier, keyedExports, data); } /** @@ -142,13 +146,17 @@ class Hooks { * @param {string} url Custom loader specifier * @param {Record} exports */ - addCustomLoader(url, exports) { + addCustomLoader(url, exports, data) { const { + initialize, globalPreload, resolve, load, } = pluckHooks(exports); + if (initialize) { + initialize(data); + } if (globalPreload) { ArrayPrototypePush(this.#chains.globalPreload, { fn: globalPreload, url }); } @@ -577,12 +585,12 @@ class HooksProxy { return body; } - makeSyncRequest(method, ...args) { + makeSyncRequest(method, args, transferList) { this.#waitForWorker(); // Pass work to the worker. debug('post sync message to worker', { method, args }); - this.#worker.postMessage({ method, args }); + this.#worker.postMessage({ method, args }, transferList); let response; do { @@ -660,12 +668,16 @@ ObjectSetPrototypeOf(HooksProxy.prototype, null); * @returns {ExportedHooks} */ function pluckHooks({ + initialize, globalPreload, resolve, load, }) { const acceptedHooks = { __proto__: null }; + if (initialize) { + acceptedHooks.initialize = initialize; + } if (globalPreload) { acceptedHooks.globalPreload = globalPreload; } diff --git a/lib/internal/modules/esm/loader.js b/lib/internal/modules/esm/loader.js index b73ba2eb3c8154..400df3e9d4902d 100644 --- a/lib/internal/modules/esm/loader.js +++ b/lib/internal/modules/esm/loader.js @@ -299,8 +299,8 @@ class CustomizedModuleLoader extends DefaultModuleLoader { * registered if using it package name as specifier * @returns {{ format: string, url: URL['href'] }} */ - register(originalSpecifier, parentURL) { - return hooksProxy.makeSyncRequest('register', originalSpecifier, parentURL); + register(originalSpecifier, options) { + return hooksProxy.makeSyncRequest('register', [originalSpecifier, options], options.transferList); } /** @@ -313,7 +313,7 @@ class CustomizedModuleLoader extends DefaultModuleLoader { * @returns {{ format: string, url: URL['href'] }} */ resolve(originalSpecifier, parentURL, importAssertions) { - return hooksProxy.makeSyncRequest('resolve', originalSpecifier, parentURL, importAssertions); + return hooksProxy.makeSyncRequest('resolve', [originalSpecifier, parentURL, importAssertions]); } async #getModuleJob(specifier, parentURL, importAssertions) { @@ -404,7 +404,7 @@ function getHooksProxy() { * register(new URL('./myLoader.js', import.meta.url)); * ``` */ -function register(specifier, parentURL = 'data:') { +function register(specifier, options = { __proto__: null }) { // TODO: Remove this limitation in a follow-up before `register` is released publicly if (getOptionValue('--experimental-loader').length < 1) { throw new ERR_ESM_LOADER_REGISTRATION_UNAVAILABLE(); @@ -412,7 +412,7 @@ function register(specifier, parentURL = 'data:') { const moduleLoader = require('internal/process/esm_loader').esmLoader; - moduleLoader.register(`${specifier}`, parentURL); + moduleLoader.register(`${specifier}`, options); } module.exports = { diff --git a/poc.loader.mjs b/poc.loader.mjs new file mode 100644 index 00000000000000..e752cf95ab308e --- /dev/null +++ b/poc.loader.mjs @@ -0,0 +1,4 @@ +export function initialize({ entryPoint, port }) { + console.log('initialize loader', { entryPoint }); + port.postMessage('loader initialized'); +} diff --git a/poc.mjs b/poc.mjs new file mode 100644 index 00000000000000..d694efcf705b5e --- /dev/null +++ b/poc.mjs @@ -0,0 +1,16 @@ +import module from 'node:module'; + +const { port1, port2 } = new MessageChannel(); + +module.register('./poc.loader.mjs', { + parentURL: import.meta.url, + data: { + entryPoint: process.argv[1], + port: port2 + }, + transferList: [port2], +}); + +port1.once('message', (message) => { + console.log(message); +}); diff --git a/test/es-module/test-esm-loader-programmatically.mjs b/test/es-module/test-esm-loader-programmatically.mjs index 0c20bbcb7519f8..73e611d3041385 100644 --- a/test/es-module/test-esm-loader-programmatically.mjs +++ b/test/es-module/test-esm-loader-programmatically.mjs @@ -15,7 +15,7 @@ const commonArgs = [ const commonEvals = { import: (module) => `await import(${JSON.stringify(module)});`, - register: (loader, parentURL = 'file:///') => `register(${JSON.stringify(loader)}, ${JSON.stringify(parentURL)});`, + register: (loader, parentURL = 'file:///') => `register(${JSON.stringify(loader)}, { parentURL: ${JSON.stringify(parentURL)} });`, dynamicImport: (module) => `await import(${JSON.stringify(`data:text/javascript,${encodeURIComponent(module)}`)});`, staticImport: (module) => `import ${JSON.stringify(`data:text/javascript,${encodeURIComponent(module)}`)};`, }; diff --git a/test/fixtures/es-module-loaders/register-programmatically-loader-resolve.mjs b/test/fixtures/es-module-loaders/register-programmatically-loader-resolve.mjs index 3ae8841da8345a..cb76eea5c550d3 100644 --- a/test/fixtures/es-module-loaders/register-programmatically-loader-resolve.mjs +++ b/test/fixtures/es-module-loaders/register-programmatically-loader-resolve.mjs @@ -1,3 +1,3 @@ import { register } from 'node:module'; -register('./loader-resolve-passthru.mjs', import.meta.url); +register('./loader-resolve-passthru.mjs', { parentURL: import.meta.url });