From 590129d31b9b0b8c159bc46d58bb813500eb7856 Mon Sep 17 00:00:00 2001 From: Jacob Smith <3012099+JakobJingleheimer@users.noreply.github.com> Date: Sun, 13 Aug 2023 19:03:22 +0200 Subject: [PATCH 01/21] esm: remove `globalPreload` hook (superseded by `initialize`) --- lib/internal/modules/esm/hooks.js | 66 ++----------------- lib/internal/modules/esm/utils.js | 4 +- test/es-module/test-esm-loader-hooks.mjs | 2 +- .../es-module-loaders/loader-side-effect.mjs | 32 --------- 4 files changed, 7 insertions(+), 97 deletions(-) delete mode 100644 test/fixtures/es-module-loaders/loader-side-effect.mjs diff --git a/lib/internal/modules/esm/hooks.js b/lib/internal/modules/esm/hooks.js index 05885050b82fc9..11dda38c5727d4 100644 --- a/lib/internal/modules/esm/hooks.js +++ b/lib/internal/modules/esm/hooks.js @@ -74,7 +74,6 @@ let importMetaInitializer; /** * @typedef {object} ExportedHooks * @property {Function} initialize Customizations setup hook. - * @property {Function} globalPreload Global preload hook. * @property {Function} resolve Resolve hook. * @property {Function} load Load hook. */ @@ -89,13 +88,6 @@ let importMetaInitializer; class Hooks { #chains = { - /** - * Prior to ESM loading. These are called once before any modules are started. - * @private - * @property {KeyedHook[]} globalPreload Last-in-first-out list of preload hooks. - */ - globalPreload: [], - /** * Phase 1 of 2 in ESM loading. * The output of the `resolve` chain of hooks is passed into the `load` chain of hooks. @@ -155,18 +147,11 @@ class Hooks { */ addCustomLoader(url, exports, data) { const { - globalPreload, initialize, resolve, load, } = pluckHooks(exports); - if (globalPreload && !initialize) { - emitExperimentalWarning( - '`globalPreload` is planned for removal in favor of `initialize`. `globalPreload`', - ); - ArrayPrototypePush(this.#chains.globalPreload, { __proto__: null, fn: globalPreload, url }); - } if (resolve) { const next = this.#chains.resolve[this.#chains.resolve.length - 1]; ArrayPrototypePush(this.#chains.resolve, { __proto__: null, fn: resolve, url, next }); @@ -178,49 +163,6 @@ class Hooks { return initialize?.(data); } - /** - * Initialize `globalPreload` hooks. - */ - initializeGlobalPreload() { - const preloadScripts = []; - for (let i = this.#chains.globalPreload.length - 1; i >= 0; i--) { - const { MessageChannel } = require('internal/worker/io'); - const channel = new MessageChannel(); - const { - port1: insidePreload, - port2: insideLoader, - } = channel; - - insidePreload.unref(); - insideLoader.unref(); - - const { - fn: preload, - url: specifier, - } = this.#chains.globalPreload[i]; - - const preloaded = preload({ - port: insideLoader, - }); - - if (preloaded == null) { continue; } - - if (typeof preloaded !== 'string') { // [2] - throw new ERR_INVALID_RETURN_VALUE( - 'a string', - `${specifier} globalPreload`, - preload, - ); - } - - ArrayPrototypePush(preloadScripts, { - code: preloaded, - port: insidePreload, - }); - } - return preloadScripts; - } - /** * Resolve the location of the module. * @@ -750,9 +692,6 @@ function pluckHooks({ }) { const acceptedHooks = { __proto__: null }; - if (globalPreload) { - acceptedHooks.globalPreload = globalPreload; - } if (resolve) { acceptedHooks.resolve = resolve; } @@ -762,6 +701,11 @@ function pluckHooks({ if (initialize) { acceptedHooks.initialize = initialize; + } else if (globalPreload) { // TODO(JakobJingleheimer): Remove this when loaders go "stable". + process.emitWarning( + '`globalPreload` has been removed; use `initialize` instead.', + 'DeprecationWarning', + ); } return acceptedHooks; diff --git a/lib/internal/modules/esm/utils.js b/lib/internal/modules/esm/utils.js index 5014c99b2a9eb3..53beda69b3c62d 100644 --- a/lib/internal/modules/esm/utils.js +++ b/lib/internal/modules/esm/utils.js @@ -145,9 +145,7 @@ async function initializeHooks() { ); } - const preloadScripts = hooks.initializeGlobalPreload(); - - return { __proto__: null, hooks, preloadScripts }; + return { __proto__: null, hooks }; } module.exports = { diff --git a/test/es-module/test-esm-loader-hooks.mjs b/test/es-module/test-esm-loader-hooks.mjs index c6cc2e9778eee6..317457e2c0bc3e 100644 --- a/test/es-module/test-esm-loader-hooks.mjs +++ b/test/es-module/test-esm-loader-hooks.mjs @@ -431,7 +431,7 @@ describe('Loader hooks', { concurrency: true }, () => { fixtures.path('empty.js'), ]); - assert.strictEqual(stderr.match(/`globalPreload` is an experimental feature/g).length, 1); + assert.strictEqual(stderr.match(/`globalPreload` has been removed/g).length, 1); }); }); diff --git a/test/fixtures/es-module-loaders/loader-side-effect.mjs b/test/fixtures/es-module-loaders/loader-side-effect.mjs deleted file mode 100644 index e91cdea0527881..00000000000000 --- a/test/fixtures/es-module-loaders/loader-side-effect.mjs +++ /dev/null @@ -1,32 +0,0 @@ -// Arrow function so it closes over the this-value of the preload scope. -const globalPreloadSrc = () => { - /* global getBuiltin */ - const assert = getBuiltin('assert'); - const vm = getBuiltin('vm'); - - assert.strictEqual(typeof require, 'undefined'); - assert.strictEqual(typeof module, 'undefined'); - assert.strictEqual(typeof exports, 'undefined'); - assert.strictEqual(typeof __filename, 'undefined'); - assert.strictEqual(typeof __dirname, 'undefined'); - - assert.strictEqual(this, globalThis); - (globalThis.preloadOrder || (globalThis.preloadOrder = [])).push('loader'); - - vm.runInThisContext(`\ -var implicitGlobalProperty = 42; -const implicitGlobalConst = 42 * 42; -`); - - assert.strictEqual(globalThis.implicitGlobalProperty, 42); - (implicitGlobalProperty).foo = 'bar'; // assert: not strict mode - - globalThis.explicitGlobalProperty = 42 * 42 * 42; -} - -export function globalPreload() { - return `\ - -(${globalPreloadSrc.toString()})(); -`; -} From d31c02face6d376a2ff648ee27a0b532b065558f Mon Sep 17 00:00:00 2001 From: Jacob Smith <3012099+JakobJingleheimer@users.noreply.github.com> Date: Sun, 20 Aug 2023 17:12:10 +0200 Subject: [PATCH 02/21] remove 'preload' execution --- lib/internal/modules/esm/hooks.js | 60 ------------------------------ lib/internal/modules/esm/worker.js | 6 +-- 2 files changed, 3 insertions(+), 63 deletions(-) diff --git a/lib/internal/modules/esm/hooks.js b/lib/internal/modules/esm/hooks.js index 11dda38c5727d4..dcaa487511dade 100644 --- a/lib/internal/modules/esm/hooks.js +++ b/lib/internal/modules/esm/hooks.js @@ -138,7 +138,6 @@ class Hooks { /** * Collect custom/user-defined module loader hook(s). - * After all hooks have been collected, the global preload hook(s) must be initialized. * @param {string} url Custom loader specifier * @param {Record} exports * @param {any} [data] Arbitrary data to be passed from the custom loader (user-land) @@ -501,8 +500,6 @@ class HooksProxy { AtomicsWait(this.#lock, WORKER_TO_MAIN_THREAD_NOTIFICATION, 0); const response = this.#worker.receiveMessageSync(); if (response == null || response.message.status === 'exit') { return; } - const { preloadScripts } = this.#unwrapMessage(response); - this.#executePreloadScripts(preloadScripts); } this.#isReady = true; @@ -619,63 +616,6 @@ class HooksProxy { importMetaInitialize(meta, context, loader) { this.#importMetaInitializer(meta, context, loader); } - - #executePreloadScripts(preloadScripts) { - for (let i = 0; i < preloadScripts.length; i++) { - const { code, port } = preloadScripts[i]; - const { compileFunction } = require('vm'); - const preloadInit = compileFunction( - code, - ['getBuiltin', 'port', 'setImportMetaCallback'], - { - filename: '', - }, - ); - let finished = false; - let replacedImportMetaInitializer = false; - let next = this.#importMetaInitializer; - const { BuiltinModule } = require('internal/bootstrap/realm'); - // Calls the compiled preload source text gotten from the hook - // Since the parameters are named we use positional parameters - // see compileFunction above to cross reference the names - try { - FunctionPrototypeCall( - preloadInit, - globalThis, - // Param getBuiltin - (builtinName) => { - if (StringPrototypeStartsWith(builtinName, 'node:')) { - builtinName = StringPrototypeSlice(builtinName, 5); - } else if (!BuiltinModule.canBeRequiredWithoutScheme(builtinName)) { - throw new ERR_UNKNOWN_BUILTIN_MODULE(builtinName); - } - if (BuiltinModule.canBeRequiredByUsers(builtinName)) { - return require(builtinName); - } - throw new ERR_UNKNOWN_BUILTIN_MODULE(builtinName); - }, - // Param port - port, - // setImportMetaCallback - (fn) => { - if (finished || typeof fn !== 'function') { - throw new ERR_INVALID_ARG_TYPE('fn', fn); - } - replacedImportMetaInitializer = true; - const parent = next; - next = (meta, context) => { - return fn(meta, context, parent); - }; - }, - ); - } finally { - finished = true; - if (replacedImportMetaInitializer) { - this.#importMetaInitializer = next; - } - } - } - } } ObjectSetPrototypeOf(HooksProxy.prototype, null); diff --git a/lib/internal/modules/esm/worker.js b/lib/internal/modules/esm/worker.js index f31820aa8f8d29..46d1cf4cb47bd3 100644 --- a/lib/internal/modules/esm/worker.js +++ b/lib/internal/modules/esm/worker.js @@ -74,7 +74,8 @@ function wrapMessage(status, body) { } async function customizedModuleWorker(lock, syncCommPort, errorHandler) { - let hooks, preloadScripts, initializationError; + let hooks; + let initializationError; let hasInitializationError = false; { @@ -93,7 +94,6 @@ async function customizedModuleWorker(lock, syncCommPort, errorHandler) { try { const initResult = await initializeHooks(); hooks = initResult.hooks; - preloadScripts = initResult.preloadScripts; } catch (exception) { // If there was an error while parsing and executing a user loader, for example if because a // loader contained a syntax error, then we need to send the error to the main thread so it can @@ -107,7 +107,7 @@ async function customizedModuleWorker(lock, syncCommPort, errorHandler) { if (hasInitializationError) { syncCommPort.postMessage(wrapMessage('error', initializationError)); } else { - syncCommPort.postMessage(wrapMessage('success', { preloadScripts }), preloadScripts.map(({ port }) => port)); + syncCommPort.postMessage(wrapMessage('success')); } // We're ready, so unlock the main thread. From 806669097990267862add1210cbf4a1921a7849e Mon Sep 17 00:00:00 2001 From: Jacob Smith <3012099+JakobJingleheimer@users.noreply.github.com> Date: Sun, 20 Aug 2023 17:13:24 +0200 Subject: [PATCH 03/21] update ESM doc (remove `globalPreload` section --- doc/api/module.md | 76 ++--------------------------------------------- 1 file changed, 3 insertions(+), 73 deletions(-) diff --git a/doc/api/module.md b/doc/api/module.md index 0c20a90b43f52c..50825ceba76acf 100644 --- a/doc/api/module.md +++ b/doc/api/module.md @@ -149,6 +149,9 @@ import('node:fs').then((esmFS) => { - -> Stability: 1.0 - Early development - -> **Warning:** This hook will be removed in a future version. Use -> [`initialize`][] instead. When a hooks module has an `initialize` export, -> `globalPreload` will be ignored. - -* `context` {Object} Information to assist the preload code - * `port` {MessagePort} -* Returns: {string} Code to run before application startup - -Sometimes it might be necessary to run some code inside of the same global -scope that the application runs in. This hook allows the return of a string -that is run as a sloppy-mode script on startup. - -Similar to how CommonJS wrappers work, the code runs in an implicit function -scope. The only argument is a `require`-like function that can be used to load -builtins like "fs": `getBuiltin(request: string)`. - -If the code needs more advanced `require` features, it has to construct -its own `require` using `module.createRequire()`. - -```mjs -export function globalPreload(context) { - return `\ -globalThis.someInjectedProperty = 42; -console.log('I just set some globals!'); - -const { createRequire } = getBuiltin('module'); -const { cwd } = getBuiltin('process'); - -const require = createRequire(cwd() + '/'); -// [...] -`; -} -``` - -Another argument is provided to the preload code: `port`. This is available as a -parameter to the hook and inside of the source text returned by the hook. This -functionality has been moved to the `initialize` hook. - -Care must be taken in order to properly call [`port.ref()`][] and -[`port.unref()`][] to prevent a process from being in a state where it won't -close normally. - -```mjs -/** - * This example has the application context send a message to the hook - * and sends the message back to the application context - */ -export function globalPreload({ port }) { - port.onmessage = (evt) => { - port.postMessage(evt.data); - }; - return `\ - port.postMessage('console.log("I went to the hook and back");'); - port.onmessage = (evt) => { - eval(evt.data); - }; - `; -} -``` - ### Examples The various module customization hooks can be used together to accomplish From d57f6512f28361fd3822a2d8905afba6af4c37aa Mon Sep 17 00:00:00 2001 From: Jacob Smith <3012099+JakobJingleheimer@users.noreply.github.com> Date: Sun, 20 Aug 2023 19:37:54 +0200 Subject: [PATCH 04/21] suppress warnings in test cases --- test/es-module/test-esm-loader-not-found.mjs | 1 + test/es-module/test-esm-loader-side-effect.mjs | 2 +- test/es-module/test-esm-loader-with-syntax-error.mjs | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/test/es-module/test-esm-loader-not-found.mjs b/test/es-module/test-esm-loader-not-found.mjs index 2abaf3078d113d..d0a317a4d69f29 100644 --- a/test/es-module/test-esm-loader-not-found.mjs +++ b/test/es-module/test-esm-loader-not-found.mjs @@ -8,6 +8,7 @@ import { describe, it } from 'node:test'; describe('ESM: nonexistent loader', () => { it('should throw', async () => { const { code, stderr } = await spawnPromisified(execPath, [ + '--no-warnings', '--experimental-loader', 'i-dont-exist', fixtures.path('print-error-message.js'), diff --git a/test/es-module/test-esm-loader-side-effect.mjs b/test/es-module/test-esm-loader-side-effect.mjs index f76b10700ddc8f..a1d41203a0d8fd 100644 --- a/test/es-module/test-esm-loader-side-effect.mjs +++ b/test/es-module/test-esm-loader-side-effect.mjs @@ -1,4 +1,4 @@ -// Flags: --experimental-loader ./test/fixtures/es-module-loaders/loader-side-effect.mjs --require ./test/fixtures/es-module-loaders/loader-side-effect-require-preload.js +// Flags: --no-warnings --experimental-loader ./test/fixtures/es-module-loaders/loader-side-effect.mjs --require ./test/fixtures/es-module-loaders/loader-side-effect-require-preload.js import { allowGlobals, mustCall } from '../common/index.mjs'; import assert from 'assert'; import { fileURLToPath } from 'url'; diff --git a/test/es-module/test-esm-loader-with-syntax-error.mjs b/test/es-module/test-esm-loader-with-syntax-error.mjs index 02a96b5b9470a8..ff27b572bc233f 100644 --- a/test/es-module/test-esm-loader-with-syntax-error.mjs +++ b/test/es-module/test-esm-loader-with-syntax-error.mjs @@ -8,6 +8,7 @@ import { describe, it } from 'node:test'; describe('ESM: loader with syntax error', { concurrency: true }, () => { it('should crash the node process', async () => { const { code, stderr } = await spawnPromisified(execPath, [ + '--no-warnings', '--experimental-loader', fileURL('es-module-loaders', 'syntax-error.mjs').href, path('print-error-message.js'), From 68b46f427a9e5dcdedbd5ff9320f38d8ef90a1f1 Mon Sep 17 00:00:00 2001 From: Jacob Smith <3012099+JakobJingleheimer@users.noreply.github.com> Date: Sun, 20 Aug 2023 20:37:56 +0200 Subject: [PATCH 05/21] remove unused deps --- lib/internal/modules/esm/hooks.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/internal/modules/esm/hooks.js b/lib/internal/modules/esm/hooks.js index dcaa487511dade..fa4565592e4f19 100644 --- a/lib/internal/modules/esm/hooks.js +++ b/lib/internal/modules/esm/hooks.js @@ -3,7 +3,6 @@ const { ArrayPrototypePush, ArrayPrototypePushApply, - FunctionPrototypeCall, Int32Array, ObjectAssign, ObjectDefineProperty, @@ -11,7 +10,6 @@ const { Promise, SafeSet, StringPrototypeSlice, - StringPrototypeStartsWith, StringPrototypeToUpperCase, globalThis, } = primordials; @@ -49,7 +47,6 @@ const { validateString, } = require('internal/validators'); const { - emitExperimentalWarning, kEmptyObject, } = require('internal/util'); From 4b48ef519d8afeec5374a3b48eb9600174c953f5 Mon Sep 17 00:00:00 2001 From: Jacob Smith <3012099+JakobJingleheimer@users.noreply.github.com> Date: Sun, 20 Aug 2023 20:38:15 +0200 Subject: [PATCH 06/21] =?UTF-8?q?!includes=20=E2=86=92=20doesNotMatch?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/es-module/test-esm-loader-with-syntax-error.mjs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/es-module/test-esm-loader-with-syntax-error.mjs b/test/es-module/test-esm-loader-with-syntax-error.mjs index ff27b572bc233f..3442ecfc45e159 100644 --- a/test/es-module/test-esm-loader-with-syntax-error.mjs +++ b/test/es-module/test-esm-loader-with-syntax-error.mjs @@ -1,6 +1,6 @@ import { spawnPromisified } from '../common/index.mjs'; import { fileURL, path } from '../common/fixtures.mjs'; -import { match, ok, notStrictEqual } from 'node:assert'; +import { doesNotMatch, match, notStrictEqual } from 'node:assert'; import { execPath } from 'node:process'; import { describe, it } from 'node:test'; @@ -14,8 +14,10 @@ describe('ESM: loader with syntax error', { concurrency: true }, () => { path('print-error-message.js'), ]); + console.log(stderr); + match(stderr, /SyntaxError \[Error\]:/); - ok(!stderr.includes('Bad command or file name')); + doesNotMatch(stderr, /Bad command or file name/); notStrictEqual(code, 0); }); }); From f4a89e4b627458c74f3eee0e8bbe10128c60a788 Mon Sep 17 00:00:00 2001 From: Jacob Smith <3012099+JakobJingleheimer@users.noreply.github.com> Date: Sun, 20 Aug 2023 20:38:47 +0200 Subject: [PATCH 07/21] =?UTF-8?q?simplify=20`initializeHooks`=20return=20`?= =?UTF-8?q?{=20hooks=20}`=20=E2=86=92=20`hooks`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/internal/modules/esm/utils.js | 2 +- lib/internal/modules/esm/worker.js | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/internal/modules/esm/utils.js b/lib/internal/modules/esm/utils.js index 53beda69b3c62d..74756857f70044 100644 --- a/lib/internal/modules/esm/utils.js +++ b/lib/internal/modules/esm/utils.js @@ -145,7 +145,7 @@ async function initializeHooks() { ); } - return { __proto__: null, hooks }; + return hooks; } module.exports = { diff --git a/lib/internal/modules/esm/worker.js b/lib/internal/modules/esm/worker.js index 46d1cf4cb47bd3..0750a80a56ab78 100644 --- a/lib/internal/modules/esm/worker.js +++ b/lib/internal/modules/esm/worker.js @@ -92,8 +92,7 @@ async function customizedModuleWorker(lock, syncCommPort, errorHandler) { try { - const initResult = await initializeHooks(); - hooks = initResult.hooks; + hooks = await initializeHooks(); } catch (exception) { // If there was an error while parsing and executing a user loader, for example if because a // loader contained a syntax error, then we need to send the error to the main thread so it can From 5226236d16c63173a1b78396a255e66aa521c3e6 Mon Sep 17 00:00:00 2001 From: Jacob Smith <3012099+JakobJingleheimer@users.noreply.github.com> Date: Sun, 27 Aug 2023 13:12:30 +0200 Subject: [PATCH 08/21] WIP: exposed error? (need to remove catches, debugs, etc) --- lib/internal/modules/esm/hooks.js | 10 +++++++++- lib/internal/modules/esm/loader.js | 17 +++++++++++++++-- lib/internal/modules/esm/module_job.js | 17 +++++++++++++++-- lib/internal/modules/esm/utils.js | 18 ++++++++++++++++-- lib/internal/modules/esm/worker.js | 3 +++ .../test-esm-loader-with-syntax-error.mjs | 13 ++++++++----- 6 files changed, 66 insertions(+), 12 deletions(-) diff --git a/lib/internal/modules/esm/hooks.js b/lib/internal/modules/esm/hooks.js index fa4565592e4f19..55b9c934b12473 100644 --- a/lib/internal/modules/esm/hooks.js +++ b/lib/internal/modules/esm/hooks.js @@ -66,6 +66,9 @@ const { let debug = require('internal/util/debuglog').debuglog('esm', (fn) => { debug = fn; }); +const { writeFileSync } = require('fs'); + + let importMetaInitializer; /** @@ -125,11 +128,16 @@ class Hooks { */ async register(urlOrSpecifier, parentURL, data) { const moduleLoader = require('internal/process/esm_loader').esmLoader; +// debug('Hooks::register', { urlOrSpecifier, parentURL, data }, moduleLoader.import) const keyedExports = await moduleLoader.import( urlOrSpecifier, parentURL, kEmptyObject, - ); + ).catch((err) => { + writeFileSync(1, `Hooks::register err ${err.stack}\n`); + throw err; + }); + debug('Hooks::register imported', urlOrSpecifier, keyedExports) await this.addCustomLoader(urlOrSpecifier, keyedExports, data); } diff --git a/lib/internal/modules/esm/loader.js b/lib/internal/modules/esm/loader.js index 14b78f660f1782..920db07402bb9a 100644 --- a/lib/internal/modules/esm/loader.js +++ b/lib/internal/modules/esm/loader.js @@ -20,6 +20,10 @@ const { getDefaultConditions, } = require('internal/modules/esm/utils'); let defaultResolve, defaultLoad, defaultLoadSync, importMetaInitializer; +let debug = require('internal/util/debuglog').debuglog('esm', (fn) => { + debug = fn; +}); +const { writeFileSync } = require('fs'); function newResolveCache() { const { ResolveCache } = require('internal/modules/esm/module_map'); @@ -167,6 +171,7 @@ class ModuleLoader { */ setCustomizations(customizations) { this.#customizations = customizations; + this.isCustomized = customizations != null; if (customizations) { this.allowImportMetaResolve = customizations.allowImportMetaResolve; } else { @@ -304,9 +309,17 @@ class ModuleLoader { * @returns {Promise} */ async import(specifier, parentURL, importAssertions) { +writeFileSync(1, `ESMLoader::import specifier ${specifier}\n`); const moduleJob = await this.getModuleJob(specifier, parentURL, importAssertions); - const { module } = await moduleJob.run(); - return module.getNamespace(); +writeFileSync(1, `ESMLoader::import gotModuleJob ${JSON.stringify(moduleJob)}\n`); + const { module } = await moduleJob.run().catch((err) => { + writeFileSync(1, `ESMLoader::import moduleJob.run caught error ${err.stack}\n`) + throw err; + }); +writeFileSync(1, `ESMLoader::import gotModuleJob ${JSON.stringify(module)}\n`); + const namespace = module.getNamespace(); +writeFileSync(1, `ESMLoader::import gotModuleJob ${JSON.stringify(namespace)}\n`); + return namespace; } /** diff --git a/lib/internal/modules/esm/module_job.js b/lib/internal/modules/esm/module_job.js index 8ac5ff240bdb37..93719bfca930fe 100644 --- a/lib/internal/modules/esm/module_job.js +++ b/lib/internal/modules/esm/module_job.js @@ -27,6 +27,10 @@ const { } = require('internal/source_map/source_map_cache'); const assert = require('internal/assert'); const resolvedPromise = PromiseResolve(); +let debug = require('internal/util/debuglog').debuglog('esm', (fn) => { + debug = fn; +}); +const { writeFileSync } = require('fs'); const noop = FunctionPrototype; @@ -87,8 +91,7 @@ class ModuleJob { return job.modulePromise; }); - if (promises !== undefined) - await SafePromiseAllReturnVoid(promises); + if (promises !== undefined) await SafePromiseAllReturnVoid(promises); return SafePromiseAllReturnArrayLike(dependencyJobs); }; @@ -111,17 +114,21 @@ class ModuleJob { } async _instantiate() { + writeFileSync(1, 'ModuleJob::instantiate()\n'); const jobsInGraph = new SafeSet(); const addJobsToDependencyGraph = async (moduleJob) => { if (jobsInGraph.has(moduleJob)) { return; } jobsInGraph.add(moduleJob); + writeFileSync(1, 'ModuleJob::instantiate() getting linked jobs\n'); const dependencyJobs = await moduleJob.linked; + writeFileSync(1, 'ModuleJob::instantiate() got linked jobs\n'); return SafePromiseAllReturnVoid(dependencyJobs, addJobsToDependencyGraph); }; await addJobsToDependencyGraph(this); + writeFileSync(1, 'ModuleJob::instantiate() job added to dep graph\n'); try { if (!hasPausedEntry && this.inspectBrk) { hasPausedEntry = true; @@ -131,6 +138,7 @@ class ModuleJob { this.module.instantiate(); } } catch (e) { + writeFileSync(1, `ModuleJob::instantiate() error: ${e.stack}\n`); decorateErrorStack(e); // TODO(@bcoe): Add source map support to exception that occurs as result // of missing named export. This is currently not possible because @@ -210,12 +218,16 @@ class ModuleJob { } async run() { + writeFileSync(1, `ModuleJob::run() instantiating: ${this.url}\n`); await this.instantiate(); + writeFileSync(1, `ModuleJob::run() instantiated: ${this.url}\n`); const timeout = -1; const breakOnSigint = false; try { await this.module.evaluate(timeout, breakOnSigint); + writeFileSync(1, `ModuleJob::run() evaluation complete: ${this.module}\n`); } catch (e) { + writeFileSync(1, `ModuleJob::run() error: ${e.stack}\n`); if (e?.name === 'ReferenceError' && isCommonJSGlobalLikeNotDefinedError(e.message)) { e.message += ' in ES module scope'; @@ -237,6 +249,7 @@ class ModuleJob { 'to use the \'.cjs\' file extension.'; } } + writeFileSync(1, `ModuleJob::run() throwing error: ${e.stack}\n`); throw e; } return { __proto__: null, module: this.module }; diff --git a/lib/internal/modules/esm/utils.js b/lib/internal/modules/esm/utils.js index 74756857f70044..84c6bf85cb531d 100644 --- a/lib/internal/modules/esm/utils.js +++ b/lib/internal/modules/esm/utils.js @@ -25,6 +25,10 @@ const { getModuleFromWrap, } = require('internal/vm/module'); const assert = require('internal/assert'); +let debug = require('internal/util/debuglog').debuglog('esm', (fn) => { + debug = fn; +}); +const { writeFileSync } = require('fs'); const callbackMap = new SafeWeakMap(); function setCallbackForWrap(wrap, data) { @@ -120,12 +124,15 @@ async function initializeHooks() { cwd = '/'; } - const { Hooks } = require('internal/modules/esm/hooks'); const esmLoader = require('internal/process/esm_loader').esmLoader; const hooks = new Hooks(); +// debug('initializeHooks hooks:', hooks); +// debug('initializeHooks between hooks & esmLoader'); +// debug('initializeHooks esmLoader:', esmLoader); esmLoader.setCustomizations(hooks); +// debug('initializeHooks customization set'); // We need the loader customizations to be set _before_ we start invoking // `--require`, otherwise loops can happen because a `--require` script @@ -135,15 +142,22 @@ async function initializeHooks() { // N.B. This block appears here specifically in order to ensure that // `--require` calls occur before `--loader` ones do. loadPreloadModules(); +// debug('initializeHooks loaded preload modules'); initializeFrozenIntrinsics(); +// debug('initializeHooks Frozen Intrinsics initialized'); const parentURL = pathToFileURL(cwd).href; +// debug('initializeHooks registering hooks relative to', parentURL, customLoaderURLs); for (let i = 0; i < customLoaderURLs.length; i++) { await hooks.register( customLoaderURLs[i], parentURL, - ); + ).catch((err) => { + writeFileSync(1, `initializeHooks: Error registering hooks: ${err.message}\n${err.stack}\n`); + throw err; + }); } +debug('initializeHooks finished: hooks', hooks); return hooks; } diff --git a/lib/internal/modules/esm/worker.js b/lib/internal/modules/esm/worker.js index 0750a80a56ab78..86e0f41a822174 100644 --- a/lib/internal/modules/esm/worker.js +++ b/lib/internal/modules/esm/worker.js @@ -31,6 +31,8 @@ const { } = require('internal/modules/esm/shared_constants'); const { initializeHooks } = require('internal/modules/esm/utils'); const { isMarkedAsUntransferable } = require('internal/buffer'); +const { writeFileSync } = require('fs'); + function transferArrayBuffer(hasError, source) { if (hasError || source == null) return; @@ -99,6 +101,7 @@ async function customizedModuleWorker(lock, syncCommPort, errorHandler) { // be thrown and printed. hasInitializationError = true; initializationError = exception; + writeFileSync(1, `Error initializing hooks: ${exception.stack}\n`); } syncCommPort.on('message', handleMessage); diff --git a/test/es-module/test-esm-loader-with-syntax-error.mjs b/test/es-module/test-esm-loader-with-syntax-error.mjs index 3442ecfc45e159..068e32c7fa31eb 100644 --- a/test/es-module/test-esm-loader-with-syntax-error.mjs +++ b/test/es-module/test-esm-loader-with-syntax-error.mjs @@ -7,17 +7,20 @@ import { describe, it } from 'node:test'; describe('ESM: loader with syntax error', { concurrency: true }, () => { it('should crash the node process', async () => { - const { code, stderr } = await spawnPromisified(execPath, [ + const { code, stderr, stdout } = await spawnPromisified(execPath, [ '--no-warnings', '--experimental-loader', fileURL('es-module-loaders', 'syntax-error.mjs').href, path('print-error-message.js'), ]); - console.log(stderr); + console.log('\n\nstderr', stderr); + console.log('\n\nstdout', stdout); - match(stderr, /SyntaxError \[Error\]:/); - doesNotMatch(stderr, /Bad command or file name/); - notStrictEqual(code, 0); + match('foo', /bar/); + + // match(stderr, /SyntaxError \[Error\]:/); + // doesNotMatch(stderr, /Bad command or file name/); // It should have crashed before this. + // notStrictEqual(code, 0); }); }); From bd04cb983add4c387e4e28012cc2db899761c810 Mon Sep 17 00:00:00 2001 From: Jacob Smith <3012099+JakobJingleheimer@users.noreply.github.com> Date: Tue, 29 Aug 2023 20:48:26 +0200 Subject: [PATCH 09/21] WIP --- lib/internal/modules/esm/hooks.js | 6 +++++ lib/internal/modules/esm/loader.js | 10 ++++----- lib/internal/modules/esm/module_job.js | 22 +++++++++---------- lib/internal/modules/esm/utils.js | 2 +- lib/internal/modules/esm/worker.js | 3 ++- .../test-esm-loader-with-syntax-error.mjs | 8 +++---- 6 files changed, 28 insertions(+), 23 deletions(-) diff --git a/lib/internal/modules/esm/hooks.js b/lib/internal/modules/esm/hooks.js index 55b9c934b12473..bcba8641f1938d 100644 --- a/lib/internal/modules/esm/hooks.js +++ b/lib/internal/modules/esm/hooks.js @@ -505,6 +505,9 @@ class HooksProxy { AtomicsWait(this.#lock, WORKER_TO_MAIN_THREAD_NOTIFICATION, 0); const response = this.#worker.receiveMessageSync(); if (response == null || response.message.status === 'exit') { return; } + + // ! This line catches initialization errors in the worker thread. + this.#unwrapMessage(response); } this.#isReady = true; @@ -587,8 +590,10 @@ class HooksProxy { AtomicsWait(this.#lock, WORKER_TO_MAIN_THREAD_NOTIFICATION, this.#workerNotificationLastId); this.#workerNotificationLastId = AtomicsLoad(this.#lock, WORKER_TO_MAIN_THREAD_NOTIFICATION); + writeFileSync(1, `HooksProxy::makeSyncRequest: awoken\n`); response = this.#worker.receiveMessageSync(); } while (response == null); + writeFileSync(1, `HooksProxy::makeSyncRequest: got response from worker ${JSON.stringify(response)}\n`); debug('got sync response from worker', { method, args }); if (response.message.status === 'never-settle') { process.exit(kUnfinishedTopLevelAwait); @@ -604,6 +609,7 @@ class HooksProxy { } const { status, body } = response.message; if (status === 'error') { + writeFileSync(1, `HooksProxy#unwrapMessage: got error from worker ${body}\n`); if (body == null || typeof body !== 'object') throw body; if (body.serializationFailed || body.serialized == null) { throw ERR_WORKER_UNSERIALIZABLE_ERROR(); diff --git a/lib/internal/modules/esm/loader.js b/lib/internal/modules/esm/loader.js index 920db07402bb9a..6e44f93222279d 100644 --- a/lib/internal/modules/esm/loader.js +++ b/lib/internal/modules/esm/loader.js @@ -309,16 +309,16 @@ class ModuleLoader { * @returns {Promise} */ async import(specifier, parentURL, importAssertions) { -writeFileSync(1, `ESMLoader::import specifier ${specifier}\n`); +// writeFileSync(1, `ESMLoader::import specifier ${specifier}\n`); const moduleJob = await this.getModuleJob(specifier, parentURL, importAssertions); -writeFileSync(1, `ESMLoader::import gotModuleJob ${JSON.stringify(moduleJob)}\n`); +// writeFileSync(1, `ESMLoader::import gotModuleJob ${JSON.stringify(moduleJob)}\n`); const { module } = await moduleJob.run().catch((err) => { - writeFileSync(1, `ESMLoader::import moduleJob.run caught error ${err.stack}\n`) + writeFileSync(1, `ESMLoader::import ${specifier} moduleJob.run caught error ${err.stack}\n`) throw err; }); -writeFileSync(1, `ESMLoader::import gotModuleJob ${JSON.stringify(module)}\n`); +writeFileSync(1, `ESMLoader::import ${specifier} gotModuleJob ${JSON.stringify(module)}\n`); const namespace = module.getNamespace(); -writeFileSync(1, `ESMLoader::import gotModuleJob ${JSON.stringify(namespace)}\n`); +writeFileSync(1, `ESMLoader::import ${specifier} gotModuleJob ${JSON.stringify(namespace)}\n`); return namespace; } diff --git a/lib/internal/modules/esm/module_job.js b/lib/internal/modules/esm/module_job.js index 93719bfca930fe..0aa21ecdd8fdc7 100644 --- a/lib/internal/modules/esm/module_job.js +++ b/lib/internal/modules/esm/module_job.js @@ -30,7 +30,7 @@ const resolvedPromise = PromiseResolve(); let debug = require('internal/util/debuglog').debuglog('esm', (fn) => { debug = fn; }); -const { writeFileSync } = require('fs'); +// const { writeFileSync } = require('fs'); const noop = FunctionPrototype; @@ -114,21 +114,21 @@ class ModuleJob { } async _instantiate() { - writeFileSync(1, 'ModuleJob::instantiate()\n'); + // writeFileSync(1, 'ModuleJob::instantiate()\n'); const jobsInGraph = new SafeSet(); const addJobsToDependencyGraph = async (moduleJob) => { if (jobsInGraph.has(moduleJob)) { return; } jobsInGraph.add(moduleJob); - writeFileSync(1, 'ModuleJob::instantiate() getting linked jobs\n'); + // writeFileSync(1, 'ModuleJob::instantiate() getting linked jobs\n'); const dependencyJobs = await moduleJob.linked; - writeFileSync(1, 'ModuleJob::instantiate() got linked jobs\n'); + // writeFileSync(1, 'ModuleJob::instantiate() got linked jobs\n'); return SafePromiseAllReturnVoid(dependencyJobs, addJobsToDependencyGraph); }; await addJobsToDependencyGraph(this); - writeFileSync(1, 'ModuleJob::instantiate() job added to dep graph\n'); + // writeFileSync(1, 'ModuleJob::instantiate() job added to dep graph\n'); try { if (!hasPausedEntry && this.inspectBrk) { hasPausedEntry = true; @@ -138,7 +138,7 @@ class ModuleJob { this.module.instantiate(); } } catch (e) { - writeFileSync(1, `ModuleJob::instantiate() error: ${e.stack}\n`); + // writeFileSync(1, `ModuleJob::instantiate() error: ${e.stack}\n`); decorateErrorStack(e); // TODO(@bcoe): Add source map support to exception that occurs as result // of missing named export. This is currently not possible because @@ -218,16 +218,16 @@ class ModuleJob { } async run() { - writeFileSync(1, `ModuleJob::run() instantiating: ${this.url}\n`); + // writeFileSync(1, `ModuleJob::run() instantiating: ${this.url}\n`); await this.instantiate(); - writeFileSync(1, `ModuleJob::run() instantiated: ${this.url}\n`); + // writeFileSync(1, `ModuleJob::run() instantiated: ${this.url}\n`); const timeout = -1; const breakOnSigint = false; try { await this.module.evaluate(timeout, breakOnSigint); - writeFileSync(1, `ModuleJob::run() evaluation complete: ${this.module}\n`); + // writeFileSync(1, `ModuleJob::run() evaluation complete: ${this.module}\n`); } catch (e) { - writeFileSync(1, `ModuleJob::run() error: ${e.stack}\n`); + // writeFileSync(1, `ModuleJob::run() error: ${e.stack}\n`); if (e?.name === 'ReferenceError' && isCommonJSGlobalLikeNotDefinedError(e.message)) { e.message += ' in ES module scope'; @@ -249,7 +249,7 @@ class ModuleJob { 'to use the \'.cjs\' file extension.'; } } - writeFileSync(1, `ModuleJob::run() throwing error: ${e.stack}\n`); + // writeFileSync(1, `ModuleJob::run() throwing error: ${e.stack}\n`); throw e; } return { __proto__: null, module: this.module }; diff --git a/lib/internal/modules/esm/utils.js b/lib/internal/modules/esm/utils.js index 84c6bf85cb531d..1d98277d80f5e6 100644 --- a/lib/internal/modules/esm/utils.js +++ b/lib/internal/modules/esm/utils.js @@ -153,7 +153,7 @@ async function initializeHooks() { customLoaderURLs[i], parentURL, ).catch((err) => { - writeFileSync(1, `initializeHooks: Error registering hooks: ${err.message}\n${err.stack}\n`); + writeFileSync(1, `initializeHooks: Error registering hooks: ${err.stack}\n`); throw err; }); } diff --git a/lib/internal/modules/esm/worker.js b/lib/internal/modules/esm/worker.js index 86e0f41a822174..a0b017ceeb539d 100644 --- a/lib/internal/modules/esm/worker.js +++ b/lib/internal/modules/esm/worker.js @@ -101,12 +101,13 @@ async function customizedModuleWorker(lock, syncCommPort, errorHandler) { // be thrown and printed. hasInitializationError = true; initializationError = exception; - writeFileSync(1, `Error initializing hooks: ${exception.stack}\n`); + writeFileSync(1, `[Worker] Error initializing hooks: ${exception.stack}\n`); } syncCommPort.on('message', handleMessage); if (hasInitializationError) { + writeFileSync(1, `[Worker] posting initialization error: ${initializationError}\n`); syncCommPort.postMessage(wrapMessage('error', initializationError)); } else { syncCommPort.postMessage(wrapMessage('success')); diff --git a/test/es-module/test-esm-loader-with-syntax-error.mjs b/test/es-module/test-esm-loader-with-syntax-error.mjs index 068e32c7fa31eb..b4d16769320804 100644 --- a/test/es-module/test-esm-loader-with-syntax-error.mjs +++ b/test/es-module/test-esm-loader-with-syntax-error.mjs @@ -17,10 +17,8 @@ describe('ESM: loader with syntax error', { concurrency: true }, () => { console.log('\n\nstderr', stderr); console.log('\n\nstdout', stdout); - match('foo', /bar/); - - // match(stderr, /SyntaxError \[Error\]:/); - // doesNotMatch(stderr, /Bad command or file name/); // It should have crashed before this. - // notStrictEqual(code, 0); + match(stderr, /SyntaxError \[Error\]:/); + doesNotMatch(stderr, /Bad command or file name/); // It should have crashed before this. + notStrictEqual(code, 0); }); }); From c5e09343bae1c075f2b4dcd9c52e056a89954662 Mon Sep 17 00:00:00 2001 From: Jacob Smith <3012099+JakobJingleheimer@users.noreply.github.com> Date: Fri, 1 Sep 2023 10:40:17 +0200 Subject: [PATCH 10/21] remove `writeFileSync` debugging --- lib/internal/modules/esm/hooks.js | 12 ++---------- lib/internal/modules/esm/loader.js | 11 ++--------- lib/internal/modules/esm/module_job.js | 18 +++++++----------- lib/internal/modules/esm/utils.js | 7 ++----- lib/internal/modules/esm/worker.js | 3 --- 5 files changed, 13 insertions(+), 38 deletions(-) diff --git a/lib/internal/modules/esm/hooks.js b/lib/internal/modules/esm/hooks.js index bcba8641f1938d..3b229fe81b6b53 100644 --- a/lib/internal/modules/esm/hooks.js +++ b/lib/internal/modules/esm/hooks.js @@ -66,7 +66,6 @@ const { let debug = require('internal/util/debuglog').debuglog('esm', (fn) => { debug = fn; }); -const { writeFileSync } = require('fs'); let importMetaInitializer; @@ -128,16 +127,12 @@ class Hooks { */ async register(urlOrSpecifier, parentURL, data) { const moduleLoader = require('internal/process/esm_loader').esmLoader; -// debug('Hooks::register', { urlOrSpecifier, parentURL, data }, moduleLoader.import) const keyedExports = await moduleLoader.import( urlOrSpecifier, parentURL, kEmptyObject, - ).catch((err) => { - writeFileSync(1, `Hooks::register err ${err.stack}\n`); - throw err; - }); - debug('Hooks::register imported', urlOrSpecifier, keyedExports) + ); + await this.addCustomLoader(urlOrSpecifier, keyedExports, data); } @@ -590,10 +585,8 @@ class HooksProxy { AtomicsWait(this.#lock, WORKER_TO_MAIN_THREAD_NOTIFICATION, this.#workerNotificationLastId); this.#workerNotificationLastId = AtomicsLoad(this.#lock, WORKER_TO_MAIN_THREAD_NOTIFICATION); - writeFileSync(1, `HooksProxy::makeSyncRequest: awoken\n`); response = this.#worker.receiveMessageSync(); } while (response == null); - writeFileSync(1, `HooksProxy::makeSyncRequest: got response from worker ${JSON.stringify(response)}\n`); debug('got sync response from worker', { method, args }); if (response.message.status === 'never-settle') { process.exit(kUnfinishedTopLevelAwait); @@ -609,7 +602,6 @@ class HooksProxy { } const { status, body } = response.message; if (status === 'error') { - writeFileSync(1, `HooksProxy#unwrapMessage: got error from worker ${body}\n`); if (body == null || typeof body !== 'object') throw body; if (body.serializationFailed || body.serialized == null) { throw ERR_WORKER_UNSERIALIZABLE_ERROR(); diff --git a/lib/internal/modules/esm/loader.js b/lib/internal/modules/esm/loader.js index 6e44f93222279d..af49cb9f5f1c25 100644 --- a/lib/internal/modules/esm/loader.js +++ b/lib/internal/modules/esm/loader.js @@ -23,7 +23,7 @@ let defaultResolve, defaultLoad, defaultLoadSync, importMetaInitializer; let debug = require('internal/util/debuglog').debuglog('esm', (fn) => { debug = fn; }); -const { writeFileSync } = require('fs'); + function newResolveCache() { const { ResolveCache } = require('internal/modules/esm/module_map'); @@ -309,16 +309,9 @@ class ModuleLoader { * @returns {Promise} */ async import(specifier, parentURL, importAssertions) { -// writeFileSync(1, `ESMLoader::import specifier ${specifier}\n`); const moduleJob = await this.getModuleJob(specifier, parentURL, importAssertions); -// writeFileSync(1, `ESMLoader::import gotModuleJob ${JSON.stringify(moduleJob)}\n`); - const { module } = await moduleJob.run().catch((err) => { - writeFileSync(1, `ESMLoader::import ${specifier} moduleJob.run caught error ${err.stack}\n`) - throw err; - }); -writeFileSync(1, `ESMLoader::import ${specifier} gotModuleJob ${JSON.stringify(module)}\n`); + const { module } = await moduleJob.run(); const namespace = module.getNamespace(); -writeFileSync(1, `ESMLoader::import ${specifier} gotModuleJob ${JSON.stringify(namespace)}\n`); return namespace; } diff --git a/lib/internal/modules/esm/module_job.js b/lib/internal/modules/esm/module_job.js index 0aa21ecdd8fdc7..2028b2ecad8074 100644 --- a/lib/internal/modules/esm/module_job.js +++ b/lib/internal/modules/esm/module_job.js @@ -30,7 +30,6 @@ const resolvedPromise = PromiseResolve(); let debug = require('internal/util/debuglog').debuglog('esm', (fn) => { debug = fn; }); -// const { writeFileSync } = require('fs'); const noop = FunctionPrototype; @@ -114,21 +113,20 @@ class ModuleJob { } async _instantiate() { - // writeFileSync(1, 'ModuleJob::instantiate()\n'); const jobsInGraph = new SafeSet(); const addJobsToDependencyGraph = async (moduleJob) => { if (jobsInGraph.has(moduleJob)) { return; } jobsInGraph.add(moduleJob); - // writeFileSync(1, 'ModuleJob::instantiate() getting linked jobs\n'); + const dependencyJobs = await moduleJob.linked; - // writeFileSync(1, 'ModuleJob::instantiate() got linked jobs\n'); + return SafePromiseAllReturnVoid(dependencyJobs, addJobsToDependencyGraph); }; + await addJobsToDependencyGraph(this); - // writeFileSync(1, 'ModuleJob::instantiate() job added to dep graph\n'); try { if (!hasPausedEntry && this.inspectBrk) { hasPausedEntry = true; @@ -138,7 +136,7 @@ class ModuleJob { this.module.instantiate(); } } catch (e) { - // writeFileSync(1, `ModuleJob::instantiate() error: ${e.stack}\n`); + decorateErrorStack(e); // TODO(@bcoe): Add source map support to exception that occurs as result // of missing named export. This is currently not possible because @@ -218,16 +216,14 @@ class ModuleJob { } async run() { - // writeFileSync(1, `ModuleJob::run() instantiating: ${this.url}\n`); await this.instantiate(); - // writeFileSync(1, `ModuleJob::run() instantiated: ${this.url}\n`); const timeout = -1; const breakOnSigint = false; + try { await this.module.evaluate(timeout, breakOnSigint); - // writeFileSync(1, `ModuleJob::run() evaluation complete: ${this.module}\n`); + } catch (e) { - // writeFileSync(1, `ModuleJob::run() error: ${e.stack}\n`); if (e?.name === 'ReferenceError' && isCommonJSGlobalLikeNotDefinedError(e.message)) { e.message += ' in ES module scope'; @@ -249,7 +245,7 @@ class ModuleJob { 'to use the \'.cjs\' file extension.'; } } - // writeFileSync(1, `ModuleJob::run() throwing error: ${e.stack}\n`); + throw e; } return { __proto__: null, module: this.module }; diff --git a/lib/internal/modules/esm/utils.js b/lib/internal/modules/esm/utils.js index 1d98277d80f5e6..7f576bdd03b2c9 100644 --- a/lib/internal/modules/esm/utils.js +++ b/lib/internal/modules/esm/utils.js @@ -28,7 +28,7 @@ const assert = require('internal/assert'); let debug = require('internal/util/debuglog').debuglog('esm', (fn) => { debug = fn; }); -const { writeFileSync } = require('fs'); + const callbackMap = new SafeWeakMap(); function setCallbackForWrap(wrap, data) { @@ -152,10 +152,7 @@ async function initializeHooks() { await hooks.register( customLoaderURLs[i], parentURL, - ).catch((err) => { - writeFileSync(1, `initializeHooks: Error registering hooks: ${err.stack}\n`); - throw err; - }); + ); } debug('initializeHooks finished: hooks', hooks); diff --git a/lib/internal/modules/esm/worker.js b/lib/internal/modules/esm/worker.js index a0b017ceeb539d..07c17bb0b316c6 100644 --- a/lib/internal/modules/esm/worker.js +++ b/lib/internal/modules/esm/worker.js @@ -31,7 +31,6 @@ const { } = require('internal/modules/esm/shared_constants'); const { initializeHooks } = require('internal/modules/esm/utils'); const { isMarkedAsUntransferable } = require('internal/buffer'); -const { writeFileSync } = require('fs'); function transferArrayBuffer(hasError, source) { @@ -101,13 +100,11 @@ async function customizedModuleWorker(lock, syncCommPort, errorHandler) { // be thrown and printed. hasInitializationError = true; initializationError = exception; - writeFileSync(1, `[Worker] Error initializing hooks: ${exception.stack}\n`); } syncCommPort.on('message', handleMessage); if (hasInitializationError) { - writeFileSync(1, `[Worker] posting initialization error: ${initializationError}\n`); syncCommPort.postMessage(wrapMessage('error', initializationError)); } else { syncCommPort.postMessage(wrapMessage('success')); From b906a4e8ca40187eab8fe5b757e529da896e30bb Mon Sep 17 00:00:00 2001 From: Geoffrey Booth Date: Sat, 2 Sep 2023 20:35:35 -0700 Subject: [PATCH 11/21] Delete test that only tests side effects of globalPreload --- .../es-module/test-esm-loader-side-effect.mjs | 32 ------------------- .../loader-side-effect-require-preload.js | 6 ---- 2 files changed, 38 deletions(-) delete mode 100644 test/es-module/test-esm-loader-side-effect.mjs delete mode 100644 test/fixtures/es-module-loaders/loader-side-effect-require-preload.js diff --git a/test/es-module/test-esm-loader-side-effect.mjs b/test/es-module/test-esm-loader-side-effect.mjs deleted file mode 100644 index a1d41203a0d8fd..00000000000000 --- a/test/es-module/test-esm-loader-side-effect.mjs +++ /dev/null @@ -1,32 +0,0 @@ -// Flags: --no-warnings --experimental-loader ./test/fixtures/es-module-loaders/loader-side-effect.mjs --require ./test/fixtures/es-module-loaders/loader-side-effect-require-preload.js -import { allowGlobals, mustCall } from '../common/index.mjs'; -import assert from 'assert'; -import { fileURLToPath } from 'url'; -import { Worker, isMainThread, parentPort } from 'worker_threads'; - -/* global implicitGlobalProperty */ -assert.strictEqual(globalThis.implicitGlobalProperty, 42); -allowGlobals(implicitGlobalProperty); - -/* global implicitGlobalConst */ -assert.strictEqual(implicitGlobalConst, 42 * 42); -allowGlobals(implicitGlobalConst); - -/* global explicitGlobalProperty */ -assert.strictEqual(globalThis.explicitGlobalProperty, 42 * 42 * 42); -allowGlobals(explicitGlobalProperty); - -/* global preloadOrder */ -assert.deepStrictEqual(globalThis.preloadOrder, ['--require', 'loader']); -allowGlobals(preloadOrder); - -if (isMainThread) { - const worker = new Worker(fileURLToPath(import.meta.url)); - const promise = new Promise((resolve, reject) => { - worker.on('message', resolve); - worker.on('error', reject); - }); - promise.then(mustCall()); -} else { - parentPort.postMessage('worker done'); -} diff --git a/test/fixtures/es-module-loaders/loader-side-effect-require-preload.js b/test/fixtures/es-module-loaders/loader-side-effect-require-preload.js deleted file mode 100644 index 98820b9379748e..00000000000000 --- a/test/fixtures/es-module-loaders/loader-side-effect-require-preload.js +++ /dev/null @@ -1,6 +0,0 @@ -/** - * This file is combined with `loader-side-effect.mjs` via `--require`. Its - * purpose is to test execution order of the two kinds of preload code. - */ - -(globalThis.preloadOrder || (globalThis.preloadOrder = [])).push('--require'); From 253a03dccfb088b1b02f9322a3dbf53351371781 Mon Sep 17 00:00:00 2001 From: Geoffrey Booth Date: Sat, 2 Sep 2023 21:08:21 -0700 Subject: [PATCH 12/21] Change warning type --- lib/internal/modules/esm/hooks.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/internal/modules/esm/hooks.js b/lib/internal/modules/esm/hooks.js index 3b229fe81b6b53..99e257bb02d11c 100644 --- a/lib/internal/modules/esm/hooks.js +++ b/lib/internal/modules/esm/hooks.js @@ -647,7 +647,7 @@ function pluckHooks({ } else if (globalPreload) { // TODO(JakobJingleheimer): Remove this when loaders go "stable". process.emitWarning( '`globalPreload` has been removed; use `initialize` instead.', - 'DeprecationWarning', + 'UnsupportedWarning', ); } From ebd986f68617c313262cc424e19b55e260228df8 Mon Sep 17 00:00:00 2001 From: Geoffrey Booth Date: Sat, 2 Sep 2023 21:18:22 -0700 Subject: [PATCH 13/21] Lint, cleanup --- lib/internal/modules/esm/hooks.js | 1 - lib/internal/modules/esm/loader.js | 6 +----- lib/internal/modules/esm/module_job.js | 5 +---- lib/internal/modules/esm/utils.js | 12 ------------ 4 files changed, 2 insertions(+), 22 deletions(-) diff --git a/lib/internal/modules/esm/hooks.js b/lib/internal/modules/esm/hooks.js index 99e257bb02d11c..91dd0f3f566ebd 100644 --- a/lib/internal/modules/esm/hooks.js +++ b/lib/internal/modules/esm/hooks.js @@ -31,7 +31,6 @@ const { ERR_INVALID_RETURN_VALUE, ERR_LOADER_CHAIN_INCOMPLETE, ERR_METHOD_NOT_IMPLEMENTED, - ERR_UNKNOWN_BUILTIN_MODULE, ERR_WORKER_UNSERIALIZABLE_ERROR, } = require('internal/errors').codes; const { exitCodes: { kUnfinishedTopLevelAwait } } = internalBinding('errors'); diff --git a/lib/internal/modules/esm/loader.js b/lib/internal/modules/esm/loader.js index af49cb9f5f1c25..f091ade69d1499 100644 --- a/lib/internal/modules/esm/loader.js +++ b/lib/internal/modules/esm/loader.js @@ -20,9 +20,6 @@ const { getDefaultConditions, } = require('internal/modules/esm/utils'); let defaultResolve, defaultLoad, defaultLoadSync, importMetaInitializer; -let debug = require('internal/util/debuglog').debuglog('esm', (fn) => { - debug = fn; -}); function newResolveCache() { @@ -311,8 +308,7 @@ class ModuleLoader { async import(specifier, parentURL, importAssertions) { const moduleJob = await this.getModuleJob(specifier, parentURL, importAssertions); const { module } = await moduleJob.run(); - const namespace = module.getNamespace(); - return namespace; + return module.getNamespace(); } /** diff --git a/lib/internal/modules/esm/module_job.js b/lib/internal/modules/esm/module_job.js index 2028b2ecad8074..bb786d3e72d961 100644 --- a/lib/internal/modules/esm/module_job.js +++ b/lib/internal/modules/esm/module_job.js @@ -27,9 +27,6 @@ const { } = require('internal/source_map/source_map_cache'); const assert = require('internal/assert'); const resolvedPromise = PromiseResolve(); -let debug = require('internal/util/debuglog').debuglog('esm', (fn) => { - debug = fn; -}); const noop = FunctionPrototype; @@ -90,7 +87,7 @@ class ModuleJob { return job.modulePromise; }); - if (promises !== undefined) await SafePromiseAllReturnVoid(promises); + if (promises !== undefined) { await SafePromiseAllReturnVoid(promises); } return SafePromiseAllReturnArrayLike(dependencyJobs); }; diff --git a/lib/internal/modules/esm/utils.js b/lib/internal/modules/esm/utils.js index 7f576bdd03b2c9..3bd2c871955ae4 100644 --- a/lib/internal/modules/esm/utils.js +++ b/lib/internal/modules/esm/utils.js @@ -25,10 +25,6 @@ const { getModuleFromWrap, } = require('internal/vm/module'); const assert = require('internal/assert'); -let debug = require('internal/util/debuglog').debuglog('esm', (fn) => { - debug = fn; -}); - const callbackMap = new SafeWeakMap(); function setCallbackForWrap(wrap, data) { @@ -128,11 +124,7 @@ async function initializeHooks() { const esmLoader = require('internal/process/esm_loader').esmLoader; const hooks = new Hooks(); -// debug('initializeHooks hooks:', hooks); -// debug('initializeHooks between hooks & esmLoader'); -// debug('initializeHooks esmLoader:', esmLoader); esmLoader.setCustomizations(hooks); -// debug('initializeHooks customization set'); // We need the loader customizations to be set _before_ we start invoking // `--require`, otherwise loops can happen because a `--require` script @@ -142,19 +134,15 @@ async function initializeHooks() { // N.B. This block appears here specifically in order to ensure that // `--require` calls occur before `--loader` ones do. loadPreloadModules(); -// debug('initializeHooks loaded preload modules'); initializeFrozenIntrinsics(); -// debug('initializeHooks Frozen Intrinsics initialized'); const parentURL = pathToFileURL(cwd).href; -// debug('initializeHooks registering hooks relative to', parentURL, customLoaderURLs); for (let i = 0; i < customLoaderURLs.length; i++) { await hooks.register( customLoaderURLs[i], parentURL, ); } -debug('initializeHooks finished: hooks', hooks); return hooks; } From ae94731a4cdf1e68e0bf692b0a779ab7bbdc213e Mon Sep 17 00:00:00 2001 From: Geoffrey Booth Date: Sat, 2 Sep 2023 21:51:51 -0700 Subject: [PATCH 14/21] Restore refactored hook-resolve-type test --- lib/internal/modules/esm/loader.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/internal/modules/esm/loader.js b/lib/internal/modules/esm/loader.js index f091ade69d1499..caef55fd0b726e 100644 --- a/lib/internal/modules/esm/loader.js +++ b/lib/internal/modules/esm/loader.js @@ -168,7 +168,6 @@ class ModuleLoader { */ setCustomizations(customizations) { this.#customizations = customizations; - this.isCustomized = customizations != null; if (customizations) { this.allowImportMetaResolve = customizations.allowImportMetaResolve; } else { From ad6bb1faf05734f40d8994f77e9a2067027920c0 Mon Sep 17 00:00:00 2001 From: Geoffrey Booth Date: Sat, 2 Sep 2023 22:10:43 -0700 Subject: [PATCH 15/21] Lint --- doc/api/module.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/doc/api/module.md b/doc/api/module.md index 50825ceba76acf..7cc5acb52793ae 100644 --- a/doc/api/module.md +++ b/doc/api/module.md @@ -1035,8 +1035,6 @@ returned object contains the following keys: [`Uint8Array`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array [`initialize`]: #initialize [`module`]: modules.md#the-module-object -[`port.ref()`]: worker_threads.md#portref -[`port.unref()`]: worker_threads.md#portunref [`register`]: #moduleregisterspecifier-parenturl-options [`string`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String [`util.TextDecoder`]: util.md#class-utiltextdecoder From c09582fd918e91c2a8b38c4e40a62f7c6d9b5aa1 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Thu, 7 Sep 2023 13:51:12 +0200 Subject: [PATCH 16/21] Apply suggestion from code review --- lib/internal/modules/esm/hooks.js | 6 +++++- lib/internal/modules/esm/loader.js | 1 - lib/internal/modules/esm/module_job.js | 10 ++-------- lib/internal/modules/esm/utils.js | 1 + lib/internal/modules/esm/worker.js | 1 - test/es-module/test-esm-loader-hooks.mjs | 13 ++++++++++++- test/es-module/test-esm-loader-not-found.mjs | 1 - .../es-module/test-esm-loader-with-syntax-error.mjs | 10 +++------- 8 files changed, 23 insertions(+), 20 deletions(-) diff --git a/lib/internal/modules/esm/hooks.js b/lib/internal/modules/esm/hooks.js index 91dd0f3f566ebd..4d45e3652369fa 100644 --- a/lib/internal/modules/esm/hooks.js +++ b/lib/internal/modules/esm/hooks.js @@ -621,6 +621,9 @@ class HooksProxy { } ObjectSetPrototypeOf(HooksProxy.prototype, null); +// TODO(JakobJingleheimer): Remove this when loaders go "stable". +let globalPreloadWarningWasEmitted = false; + /** * A utility function to pluck the hooks from a user-defined loader. * @param {import('./loader.js).ModuleExports} exports @@ -643,11 +646,12 @@ function pluckHooks({ if (initialize) { acceptedHooks.initialize = initialize; - } else if (globalPreload) { // TODO(JakobJingleheimer): Remove this when loaders go "stable". + } else if (globalPreload && !globalPreloadWarningWasEmitted) { process.emitWarning( '`globalPreload` has been removed; use `initialize` instead.', 'UnsupportedWarning', ); + globalPreloadWarningWasEmitted = true; } return acceptedHooks; diff --git a/lib/internal/modules/esm/loader.js b/lib/internal/modules/esm/loader.js index caef55fd0b726e..14b78f660f1782 100644 --- a/lib/internal/modules/esm/loader.js +++ b/lib/internal/modules/esm/loader.js @@ -21,7 +21,6 @@ const { } = require('internal/modules/esm/utils'); let defaultResolve, defaultLoad, defaultLoadSync, importMetaInitializer; - function newResolveCache() { const { ResolveCache } = require('internal/modules/esm/module_map'); return new ResolveCache(); diff --git a/lib/internal/modules/esm/module_job.js b/lib/internal/modules/esm/module_job.js index bb786d3e72d961..8ac5ff240bdb37 100644 --- a/lib/internal/modules/esm/module_job.js +++ b/lib/internal/modules/esm/module_job.js @@ -87,7 +87,8 @@ class ModuleJob { return job.modulePromise; }); - if (promises !== undefined) { await SafePromiseAllReturnVoid(promises); } + if (promises !== undefined) + await SafePromiseAllReturnVoid(promises); return SafePromiseAllReturnArrayLike(dependencyJobs); }; @@ -116,12 +117,9 @@ class ModuleJob { return; } jobsInGraph.add(moduleJob); - const dependencyJobs = await moduleJob.linked; - return SafePromiseAllReturnVoid(dependencyJobs, addJobsToDependencyGraph); }; - await addJobsToDependencyGraph(this); try { @@ -133,7 +131,6 @@ class ModuleJob { this.module.instantiate(); } } catch (e) { - decorateErrorStack(e); // TODO(@bcoe): Add source map support to exception that occurs as result // of missing named export. This is currently not possible because @@ -216,10 +213,8 @@ class ModuleJob { await this.instantiate(); const timeout = -1; const breakOnSigint = false; - try { await this.module.evaluate(timeout, breakOnSigint); - } catch (e) { if (e?.name === 'ReferenceError' && isCommonJSGlobalLikeNotDefinedError(e.message)) { @@ -242,7 +237,6 @@ class ModuleJob { 'to use the \'.cjs\' file extension.'; } } - throw e; } return { __proto__: null, module: this.module }; diff --git a/lib/internal/modules/esm/utils.js b/lib/internal/modules/esm/utils.js index 3bd2c871955ae4..74756857f70044 100644 --- a/lib/internal/modules/esm/utils.js +++ b/lib/internal/modules/esm/utils.js @@ -120,6 +120,7 @@ async function initializeHooks() { cwd = '/'; } + const { Hooks } = require('internal/modules/esm/hooks'); const esmLoader = require('internal/process/esm_loader').esmLoader; diff --git a/lib/internal/modules/esm/worker.js b/lib/internal/modules/esm/worker.js index 07c17bb0b316c6..0750a80a56ab78 100644 --- a/lib/internal/modules/esm/worker.js +++ b/lib/internal/modules/esm/worker.js @@ -32,7 +32,6 @@ const { const { initializeHooks } = require('internal/modules/esm/utils'); const { isMarkedAsUntransferable } = require('internal/buffer'); - function transferArrayBuffer(hasError, source) { if (hasError || source == null) return; let arrayBuffer; diff --git a/test/es-module/test-esm-loader-hooks.mjs b/test/es-module/test-esm-loader-hooks.mjs index 317457e2c0bc3e..e57e9df1104f9b 100644 --- a/test/es-module/test-esm-loader-hooks.mjs +++ b/test/es-module/test-esm-loader-hooks.mjs @@ -1,6 +1,7 @@ import { spawnPromisified } from '../common/index.mjs'; import * as fixtures from '../common/fixtures.mjs'; import assert from 'node:assert'; +import os from 'node:os'; import { execPath } from 'node:process'; import { describe, it } from 'node:test'; @@ -431,7 +432,17 @@ describe('Loader hooks', { concurrency: true }, () => { fixtures.path('empty.js'), ]); - assert.strictEqual(stderr.match(/`globalPreload` has been removed/g).length, 1); + assert.strictEqual(stderr.match(/`globalPreload` has been removed; use `initialize` instead/g).length, 1); + }); + + it('should not emit deprecation warning when initialize is supplied', async () => { + const { stderr } = await spawnPromisified(execPath, [ + '--experimental-loader', + 'data:text/javascript,export function globalPreload(){}export function initialize(){}', + fixtures.path('empty.js'), + ]); + + assert.doesNotMatch(stderr, /`globalPreload` has been removed; use `initialize` instead/); }); }); diff --git a/test/es-module/test-esm-loader-not-found.mjs b/test/es-module/test-esm-loader-not-found.mjs index d0a317a4d69f29..2abaf3078d113d 100644 --- a/test/es-module/test-esm-loader-not-found.mjs +++ b/test/es-module/test-esm-loader-not-found.mjs @@ -8,7 +8,6 @@ import { describe, it } from 'node:test'; describe('ESM: nonexistent loader', () => { it('should throw', async () => { const { code, stderr } = await spawnPromisified(execPath, [ - '--no-warnings', '--experimental-loader', 'i-dont-exist', fixtures.path('print-error-message.js'), diff --git a/test/es-module/test-esm-loader-with-syntax-error.mjs b/test/es-module/test-esm-loader-with-syntax-error.mjs index b4d16769320804..02a96b5b9470a8 100644 --- a/test/es-module/test-esm-loader-with-syntax-error.mjs +++ b/test/es-module/test-esm-loader-with-syntax-error.mjs @@ -1,24 +1,20 @@ import { spawnPromisified } from '../common/index.mjs'; import { fileURL, path } from '../common/fixtures.mjs'; -import { doesNotMatch, match, notStrictEqual } from 'node:assert'; +import { match, ok, notStrictEqual } from 'node:assert'; import { execPath } from 'node:process'; import { describe, it } from 'node:test'; describe('ESM: loader with syntax error', { concurrency: true }, () => { it('should crash the node process', async () => { - const { code, stderr, stdout } = await spawnPromisified(execPath, [ - '--no-warnings', + const { code, stderr } = await spawnPromisified(execPath, [ '--experimental-loader', fileURL('es-module-loaders', 'syntax-error.mjs').href, path('print-error-message.js'), ]); - console.log('\n\nstderr', stderr); - console.log('\n\nstdout', stdout); - match(stderr, /SyntaxError \[Error\]:/); - doesNotMatch(stderr, /Bad command or file name/); // It should have crashed before this. + ok(!stderr.includes('Bad command or file name')); notStrictEqual(code, 0); }); }); From b1db565856636b681e82eb0c3d3cab694aea2ce0 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Thu, 7 Sep 2023 14:13:17 +0200 Subject: [PATCH 17/21] lint --- test/es-module/test-esm-loader-hooks.mjs | 1 - 1 file changed, 1 deletion(-) diff --git a/test/es-module/test-esm-loader-hooks.mjs b/test/es-module/test-esm-loader-hooks.mjs index e57e9df1104f9b..1c883c0b2141f1 100644 --- a/test/es-module/test-esm-loader-hooks.mjs +++ b/test/es-module/test-esm-loader-hooks.mjs @@ -1,7 +1,6 @@ import { spawnPromisified } from '../common/index.mjs'; import * as fixtures from '../common/fixtures.mjs'; import assert from 'node:assert'; -import os from 'node:os'; import { execPath } from 'node:process'; import { describe, it } from 'node:test'; From c5eaaebd26b79b4719e8c2f453e1554f7b5d144f Mon Sep 17 00:00:00 2001 From: Geoffrey Booth Date: Thu, 7 Sep 2023 14:57:37 -0700 Subject: [PATCH 18/21] Update lib/internal/modules/esm/hooks.js --- lib/internal/modules/esm/hooks.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/internal/modules/esm/hooks.js b/lib/internal/modules/esm/hooks.js index 4d45e3652369fa..ac57a939445397 100644 --- a/lib/internal/modules/esm/hooks.js +++ b/lib/internal/modules/esm/hooks.js @@ -65,8 +65,6 @@ const { let debug = require('internal/util/debuglog').debuglog('esm', (fn) => { debug = fn; }); - - let importMetaInitializer; /** From 8e39882241ef77dff4e211b42583fea11939238a Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Sat, 9 Sep 2023 00:01:18 +0200 Subject: [PATCH 19/21] Update lib/internal/modules/esm/hooks.js --- lib/internal/modules/esm/hooks.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/internal/modules/esm/hooks.js b/lib/internal/modules/esm/hooks.js index ac57a939445397..d1b5a0497b6f8d 100644 --- a/lib/internal/modules/esm/hooks.js +++ b/lib/internal/modules/esm/hooks.js @@ -69,7 +69,6 @@ let importMetaInitializer; /** * @typedef {object} ExportedHooks - * @property {Function} initialize Customizations setup hook. * @property {Function} resolve Resolve hook. * @property {Function} load Load hook. */ From 05a88fdd9e3cd717c134b29816989929649a6c95 Mon Sep 17 00:00:00 2001 From: Geoffrey Booth Date: Sat, 9 Sep 2023 18:37:04 -0700 Subject: [PATCH 20/21] Fixup --- lib/internal/modules/esm/hooks.js | 1 - test/es-module/test-esm-loader-hooks.mjs | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/internal/modules/esm/hooks.js b/lib/internal/modules/esm/hooks.js index d1b5a0497b6f8d..87325ef4f71edf 100644 --- a/lib/internal/modules/esm/hooks.js +++ b/lib/internal/modules/esm/hooks.js @@ -128,7 +128,6 @@ class Hooks { parentURL, kEmptyObject, ); - await this.addCustomLoader(urlOrSpecifier, keyedExports, data); } diff --git a/test/es-module/test-esm-loader-hooks.mjs b/test/es-module/test-esm-loader-hooks.mjs index 1c883c0b2141f1..7ff1fc520d90b5 100644 --- a/test/es-module/test-esm-loader-hooks.mjs +++ b/test/es-module/test-esm-loader-hooks.mjs @@ -434,7 +434,7 @@ describe('Loader hooks', { concurrency: true }, () => { assert.strictEqual(stderr.match(/`globalPreload` has been removed; use `initialize` instead/g).length, 1); }); - it('should not emit deprecation warning when initialize is supplied', async () => { + it('should not emit warning when initialize is supplied', async () => { const { stderr } = await spawnPromisified(execPath, [ '--experimental-loader', 'data:text/javascript,export function globalPreload(){}export function initialize(){}', From 42e63213b87f351bbf5b1e46098c5a245756369e Mon Sep 17 00:00:00 2001 From: Geoffrey Booth Date: Sat, 9 Sep 2023 18:43:21 -0700 Subject: [PATCH 21/21] Remove isolated file --- .../test-esm-loader-globalpreload-hook.mjs | 149 ------------------ 1 file changed, 149 deletions(-) delete mode 100644 test/es-module/test-esm-loader-globalpreload-hook.mjs diff --git a/test/es-module/test-esm-loader-globalpreload-hook.mjs b/test/es-module/test-esm-loader-globalpreload-hook.mjs deleted file mode 100644 index 87def31fb3d0ea..00000000000000 --- a/test/es-module/test-esm-loader-globalpreload-hook.mjs +++ /dev/null @@ -1,149 +0,0 @@ -import { spawnPromisified } from '../common/index.mjs'; -import * as fixtures from '../common/fixtures.mjs'; -import assert from 'node:assert'; -import os from 'node:os'; -import { execPath } from 'node:process'; -import { describe, it } from 'node:test'; - -describe('globalPreload hook', () => { - it('should not emit deprecation warning when initialize is supplied', async () => { - const { stderr } = await spawnPromisified(execPath, [ - '--experimental-loader', - 'data:text/javascript,export function globalPreload(){}export function initialize(){}', - fixtures.path('empty.js'), - ]); - - assert.doesNotMatch(stderr, /`globalPreload` is an experimental feature/); - }); - - it('should handle globalPreload returning undefined', async () => { - const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [ - '--no-warnings', - '--experimental-loader', - 'data:text/javascript,export function globalPreload(){}', - fixtures.path('empty.js'), - ]); - - assert.strictEqual(stderr, ''); - assert.strictEqual(stdout, ''); - assert.strictEqual(code, 0); - assert.strictEqual(signal, null); - }); - - it('should handle loading node:test', async () => { - const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [ - '--no-warnings', - '--experimental-loader', - 'data:text/javascript,export function globalPreload(){return `getBuiltin("node:test")()`}', - fixtures.path('empty.js'), - ]); - - assert.strictEqual(stderr, ''); - assert.match(stdout, /\n# pass 1\r?\n/); - assert.strictEqual(code, 0); - assert.strictEqual(signal, null); - }); - - it('should handle loading node:os with node: prefix', async () => { - const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [ - '--no-warnings', - '--experimental-loader', - 'data:text/javascript,export function globalPreload(){return `console.log(getBuiltin("node:os").arch())`}', - fixtures.path('empty.js'), - ]); - - assert.strictEqual(stderr, ''); - assert.strictEqual(stdout.trim(), os.arch()); - assert.strictEqual(code, 0); - assert.strictEqual(signal, null); - }); - - // `os` is used here because it's simple and not mocked (the builtin module otherwise doesn't matter). - it('should handle loading builtin module without node: prefix', async () => { - const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [ - '--no-warnings', - '--experimental-loader', - 'data:text/javascript,export function globalPreload(){return `console.log(getBuiltin("os").arch())`}', - fixtures.path('empty.js'), - ]); - - assert.strictEqual(stderr, ''); - assert.strictEqual(stdout.trim(), os.arch()); - assert.strictEqual(code, 0); - assert.strictEqual(signal, null); - }); - - it('should throw when loading node:test without node: prefix', async () => { - const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [ - '--no-warnings', - '--experimental-loader', - 'data:text/javascript,export function globalPreload(){return `getBuiltin("test")()`}', - fixtures.path('empty.js'), - ]); - - assert.match(stderr, /ERR_UNKNOWN_BUILTIN_MODULE/); - assert.strictEqual(stdout, ''); - assert.strictEqual(code, 1); - assert.strictEqual(signal, null); - }); - - it('should register globals set from globalPreload', async () => { - const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [ - '--no-warnings', - '--experimental-loader', - 'data:text/javascript,export function globalPreload(){return "this.myGlobal=4"}', - '--print', 'myGlobal', - ]); - - assert.strictEqual(stderr, ''); - assert.strictEqual(stdout.trim(), '4'); - assert.strictEqual(code, 0); - assert.strictEqual(signal, null); - }); - - it('should log console.log calls returned from globalPreload', async () => { - const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [ - '--no-warnings', - '--experimental-loader', - 'data:text/javascript,export function globalPreload(){return `console.log("Hello from globalPreload")`}', - fixtures.path('empty.js'), - ]); - - assert.strictEqual(stderr, ''); - assert.strictEqual(stdout.trim(), 'Hello from globalPreload'); - assert.strictEqual(code, 0); - assert.strictEqual(signal, null); - }); - - it('should crash if globalPreload returns code that throws', async () => { - const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [ - '--no-warnings', - '--experimental-loader', - 'data:text/javascript,export function globalPreload(){return `throw new Error("error from globalPreload")`}', - fixtures.path('empty.js'), - ]); - - assert.match(stderr, /error from globalPreload/); - assert.strictEqual(stdout, ''); - assert.strictEqual(code, 1); - assert.strictEqual(signal, null); - }); - - it('should have a `this` value that is not bound to the loader instance', async () => { - const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [ - '--no-warnings', - '--experimental-loader', - `data:text/javascript,export ${function globalPreload() { - if (this != null) { - throw new Error('hook function must not be bound to ESMLoader instance'); - } - }}`, - fixtures.path('empty.js'), - ]); - - assert.strictEqual(stderr, ''); - assert.strictEqual(stdout, ''); - assert.strictEqual(code, 0); - assert.strictEqual(signal, null); - }); -});