| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 064c8c5 commit 2d48d17
9 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -11,15 +11,14 @@ const { | |||
| 11 | 11 | ObjectDefineProperty, | |
| 12 | 12 | PromisePrototypeThen, | |
| 13 | 13 | RegExpPrototypeExec, | |
| 14 | - SafeWeakMap, | ||
| 15 | 14 | globalThis: { | |
| 16 | 15 | SharedArrayBuffer, | |
| 17 | 16 | }, | |
| 18 | 17 | } = primordials; | |
| 19 | 18 | ||
| 20 | 19 | const { | |
| 21 | 20 | prepareWorkerThreadExecution, | |
| 22 | - setupUserModules, | ||
| 21 | + initializeModuleLoaders, | ||
| 23 | 22 | markBootstrapComplete, | |
| 24 | 23 | } = require('internal/process/pre_execution'); | |
| 25 | 24 | ||
@@ -138,11 +137,13 @@ port.on('message', (message) => { | |||
| 138 | 137 | workerIo.sharedCwdCounter = cwdCounter; | |
| 139 | 138 | } | |
| 140 | 139 | ||
| 141 | - const isLoaderWorker = | ||
| 142 | - doEval === 'internal' && | ||
| 143 | - filename === require('internal/modules/esm/utils').loaderWorkerId; | ||
| 144 | - // Disable custom loaders in loader worker. | ||
| 145 | - setupUserModules(isLoaderWorker); | ||
| 140 | + const isLoaderHookWorker = (filename === 'internal/modules/esm/worker' && doEval === 'internal'); | ||
| 141 | + if (!isLoaderHookWorker) { | ||
| 142 | + // If we are in the loader hook worker, delay the module loader initializations until | ||
| 143 | + // initializeAsyncLoaderHooksOnLoaderHookWorker() which needs to run preloads | ||
| 144 | + // after the asynchronous loader hooks are registered. | ||
| 145 | + initializeModuleLoaders({ shouldSpawnLoaderHookWorker: true, shouldPreloadModules: true }); | ||
| 146 | + } | ||
| 146 | 147 | ||
| 147 | 148 | if (!hasStdin) | |
| 148 | 149 | process.stdin.push(null); | |
@@ -152,9 +153,10 @@ port.on('message', (message) => { | |||
| 152 | 153 | port.postMessage({ type: UP_AND_RUNNING }); | |
| 153 | 154 | switch (doEval) { | |
| 154 | 155 | case 'internal': { | |
| 155 | - // Create this WeakMap in js-land because V8 has no C++ API for WeakMap. | ||
| 156 | - internalBinding('module_wrap').callbackMap = new SafeWeakMap(); | ||
| 157 | - require(filename)(workerData, publicPort); | ||
| 156 | + // Currently the only user of internal eval is the async loader hook thread. | ||
| 157 | + assert(isLoaderHookWorker, `Unexpected internal eval ${filename}`); | ||
| 158 | + const setupModuleWorker = require('internal/modules/esm/worker'); | ||
| 159 | + setupModuleWorker(workerData, publicPort); | ||
| 158 | 160 | break; | |
| 159 | 161 | } | |
| 160 | 162 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -54,7 +54,6 @@ const { | |||
| 54 | 54 | } = require('internal/modules/esm/resolve'); | |
| 55 | 55 | const { | |
| 56 | 56 | getDefaultConditions, | |
| 57 | - loaderWorkerId, | ||
| 58 | 57 | } = require('internal/modules/esm/utils'); | |
| 59 | 58 | const { deserializeError } = require('internal/error_serdes'); | |
| 60 | 59 | const { | |
@@ -105,7 +104,39 @@ function defineImportAssertionAlias(context) { | |||
| 105 | 104 | ||
| 106 | 105 | // [2] `validate...()`s throw the wrong error | |
| 107 | 106 | ||
| 108 | - class Hooks { | ||
| 107 | + /** | ||
| 108 | + * @typedef {{ format: ModuleFormat, source: ModuleSource }} LoadResult | ||
| 109 | + */ | ||
| 110 | + | ||
| 111 | + /** | ||
| 112 | + * @typedef {{ format: ModuleFormat, url: string, importAttributes: Record<string, string> }} ResolveResult | ||
| 113 | + */ | ||
| 114 | + | ||
| 115 | + /** | ||
| 116 | + * Interface for classes that implement asynchronous loader hooks that can be attached to the ModuleLoader | ||
| 117 | + * via `ModuleLoader.#setAsyncLoaderHooks()`. | ||
| 118 | + * @typedef {object} AsyncLoaderHooks | ||
| 119 | + * @property {boolean} allowImportMetaResolve Whether to allow the use of `import.meta.resolve`. | ||
| 120 | + * @property {(url: string, context: object, defaultLoad: Function) => Promise<LoadResult>} load | ||
| 121 | + * Calling the asynchronous `load` hook asynchronously. | ||
| 122 | + * @property {(url: string, context: object, defaultLoad: Function) => LoadResult} loadSync | ||
| 123 | + * Calling the asynchronous `load` hook synchronously. | ||
| 124 | + * @property {(originalSpecifier: string, parentURL: string, | ||
| 125 | + * importAttributes: Record<string, string>) => Promise<ResolveResult>} resolve | ||
| 126 | + * Calling the asynchronous `resolve` hook asynchronously. | ||
| 127 | + * @property {(originalSpecifier: string, parentURL: string, | ||
| 128 | + * importAttributes: Record<string, string>) => ResolveResult} resolveSync | ||
| 129 | + * Calling the asynchronous `resolve` hook synchronously. | ||
| 130 | + * @property {(specifier: string, parentURL: string) => any} register Register asynchronous loader hooks | ||
| 131 | + * @property {() => void} waitForLoaderHookInitialization Force loading of hooks. | ||
| 132 | + */ | ||
| 133 | + | ||
| 134 | + /** | ||
| 135 | + * @implements {AsyncLoaderHooks} | ||
| 136 | + * Instances of this class run directly on the loader hook worker thread and customize the module | ||
| 137 | + * loading of the hooks worker itself. | ||
| 138 | + */ | ||
| 139 | + class AsyncLoaderHooksOnLoaderHookWorker { | ||
| 109 | 140 | #chains = { | |
| 110 | 141 | /** | |
| 111 | 142 | * Phase 1 of 2 in ESM loading. | |
@@ -452,7 +483,7 @@ class Hooks { | |||
| 452 | 483 | }; | |
| 453 | 484 | } | |
| 454 | 485 | ||
| 455 | - forceLoadHooks() { | ||
| 486 | + waitForLoaderHookInitialization() { | ||
| 456 | 487 | // No-op | |
| 457 | 488 | } | |
| 458 | 489 | ||
@@ -462,14 +493,20 @@ class Hooks { | |||
| 462 | 493 | return meta; | |
| 463 | 494 | } | |
| 464 | 495 | } | |
| 465 | - ObjectSetPrototypeOf(Hooks.prototype, null); | ||
| 496 | + ObjectSetPrototypeOf(AsyncLoaderHooksOnLoaderHookWorker.prototype, null); | ||
| 466 | 497 | ||
| 467 | 498 | /** | |
| 468 | - * There may be multiple instances of Hooks/HooksProxy, but there is only 1 Internal worker, so | ||
| 469 | - * there is only 1 MessageChannel. | ||
| 499 | + * There is only one loader hook thread for each non-loader-hook worker thread | ||
| 500 | + * (i.e. the non-loader-hook thread and any worker threads that are not loader hook workers themselves), | ||
| 501 | + * so there is only 1 MessageChannel. | ||
| 470 | 502 | */ | |
| 471 | 503 | let MessageChannel; | |
| 472 | - class HooksProxy { | ||
| 504 | + | ||
| 505 | + /** | ||
| 506 | + * Abstraction over a worker thread that runs the asynchronous module loader hooks. | ||
| 507 | + * Instances of this class run on the non-loader-hook thread and communicate with the loader hooks worker thread. | ||
| 508 | + */ | ||
| 509 | + class AsyncLoaderHookWorker { | ||
| 473 | 510 | /** | |
| 474 | 511 | * Shared memory. Always use Atomics method to read or write to it. | |
| 475 | 512 | * @type {Int32Array} | |
@@ -503,7 +540,7 @@ class HooksProxy { | |||
| 503 | 540 | const lock = new SharedArrayBuffer(SHARED_MEMORY_BYTE_LENGTH); | |
| 504 | 541 | this.#lock = new Int32Array(lock); | |
| 505 | 542 | ||
| 506 | - this.#worker = new InternalWorker(loaderWorkerId, { | ||
| 543 | + this.#worker = new InternalWorker('internal/modules/esm/worker', { | ||
| 507 | 544 | stderr: false, | |
| 508 | 545 | stdin: false, | |
| 509 | 546 | stdout: false, | |
@@ -644,7 +681,7 @@ class HooksProxy { | |||
| 644 | 681 | this.#importMetaInitializer(meta, context, loader); | |
| 645 | 682 | } | |
| 646 | 683 | } | |
| 647 | - ObjectSetPrototypeOf(HooksProxy.prototype, null); | ||
| 684 | + ObjectSetPrototypeOf(AsyncLoaderHookWorker.prototype, null); | ||
| 648 | 685 | ||
| 649 | 686 | // TODO(JakobJingleheimer): Remove this when loaders go "stable". | |
| 650 | 687 | let globalPreloadWarningWasEmitted = false; | |
@@ -757,6 +794,95 @@ function nextHookFactory(current, meta, { validateArgs, validateOutput }) { | |||
| 757 | 794 | ); | |
| 758 | 795 | } | |
| 759 | 796 | ||
| 797 | + /** | ||
| 798 | + * @type {AsyncLoaderHookWorker} | ||
| 799 | + * Worker instance used to run async loader hooks in a separate thread. This is a singleton for each | ||
| 800 | + * non-loader-hook worker thread (i.e. the main thread and any worker threads that are not | ||
| 801 | + * loader hook workers themselves). | ||
| 802 | + */ | ||
| 803 | + let asyncLoaderHookWorker; | ||
| 804 | + /** | ||
| 805 | + * Get the AsyncLoaderHookWorker instance. If it is not defined, then create a new one. | ||
| 806 | + * @returns {AsyncLoaderHookWorker} | ||
| 807 | + */ | ||
| 808 | + function getAsyncLoaderHookWorker() { | ||
| 809 | + asyncLoaderHookWorker ??= new AsyncLoaderHookWorker(); | ||
| 810 | + return asyncLoaderHookWorker; | ||
| 811 | + } | ||
| 812 | + | ||
| 813 | + /** | ||
| 814 | + * @implements {AsyncLoaderHooks} | ||
| 815 | + * Instances of this class are created in the non-loader-hook thread and communicate with the worker thread | ||
| 816 | + * spawned to run the async loader hooks. | ||
| 817 | + */ | ||
| 818 | + class AsyncLoaderHooksProxiedToLoaderHookWorker { | ||
| 819 | + | ||
| 820 | + allowImportMetaResolve = true; | ||
| 821 | + | ||
| 822 | + /** | ||
| 823 | + * Instantiate a module loader that uses user-provided custom loader hooks. | ||
| 824 | + */ | ||
| 825 | + constructor() { | ||
| 826 | + getAsyncLoaderHookWorker(); | ||
| 827 | + } | ||
| 828 | + | ||
| 829 | + /** | ||
| 830 | + * Register some loader specifier. | ||
| 831 | + * @param {string} originalSpecifier The specified URL path of the loader to | ||
| 832 | + * be registered. | ||
| 833 | + * @param {string} parentURL The parent URL from where the loader will be | ||
| 834 | + * registered if using it package name as specifier | ||
| 835 | + * @param {any} [data] Arbitrary data to be passed from the custom loader | ||
| 836 | + * (user-land) to the worker. | ||
| 837 | + * @param {any[]} [transferList] Objects in `data` that are changing ownership | ||
| 838 | + * @param {boolean} [isInternal] For internal loaders that should not be publicly exposed. | ||
| 839 | + * @returns {{ format: string, url: URL['href'] }} | ||
| 840 | + */ | ||
| 841 | + register(originalSpecifier, parentURL, data, transferList, isInternal) { | ||
| 842 | + return asyncLoaderHookWorker.makeSyncRequest('register', transferList, originalSpecifier, parentURL, | ||
| 843 | + data, isInternal); | ||
| 844 | + } | ||
| 845 | + | ||
| 846 | + /** | ||
| 847 | + * Resolve the location of the module. | ||
| 848 | + * @param {string} originalSpecifier The specified URL path of the module to | ||
| 849 | + * be resolved. | ||
| 850 | + * @param {string} [parentURL] The URL path of the module's parent. | ||
| 851 | + * @param {ImportAttributes} importAttributes Attributes from the import | ||
| 852 | + * statement or expression. | ||
| 853 | + * @returns {{ format: string, url: URL['href'] }} | ||
| 854 | + */ | ||
| 855 | + resolve(originalSpecifier, parentURL, importAttributes) { | ||
| 856 | + return asyncLoaderHookWorker.makeAsyncRequest('resolve', undefined, originalSpecifier, parentURL, importAttributes); | ||
| 857 | + } | ||
| 858 | + | ||
| 859 | + resolveSync(originalSpecifier, parentURL, importAttributes) { | ||
| 860 | + // This happens only as a result of `import.meta.resolve` calls, which must be sync per spec. | ||
| 861 | + return asyncLoaderHookWorker.makeSyncRequest('resolve', undefined, originalSpecifier, parentURL, importAttributes); | ||
| 862 | + } | ||
| 863 | + | ||
| 864 | + /** | ||
| 865 | + * Provide source that is understood by one of Node's translators. | ||
| 866 | + * @param {URL['href']} url The URL/path of the module to be loaded | ||
| 867 | + * @param {object} [context] Metadata about the module | ||
| 868 | + * @returns {Promise<{ format: ModuleFormat, source: ModuleSource }>} | ||
| 869 | + */ | ||
| 870 | + load(url, context) { | ||
| 871 | + return asyncLoaderHookWorker.makeAsyncRequest('load', undefined, url, context); | ||
| 872 | + } | ||
| 873 | + loadSync(url, context) { | ||
| 874 | + return asyncLoaderHookWorker.makeSyncRequest('load', undefined, url, context); | ||
| 875 | + } | ||
| 876 | + | ||
| 877 | + importMetaInitialize(meta, context, loader) { | ||
| 878 | + asyncLoaderHookWorker.importMetaInitialize(meta, context, loader); | ||
| 879 | + } | ||
| 880 | + | ||
| 881 | + waitForLoaderHookInitialization() { | ||
| 882 | + asyncLoaderHookWorker.waitForWorker(); | ||
| 883 | + } | ||
| 884 | + } | ||
| 760 | 885 | ||
| 761 | - exports.Hooks = Hooks; | ||
| 762 | - exports.HooksProxy = HooksProxy; | ||
| 886 | + exports.AsyncLoaderHooksProxiedToLoaderHookWorker = AsyncLoaderHooksProxiedToLoaderHookWorker; | ||
| 887 | + exports.AsyncLoaderHooksOnLoaderHookWorker = AsyncLoaderHooksOnLoaderHookWorker; | ||
| 888 | + exports.AsyncLoaderHookWorker = AsyncLoaderHookWorker; | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments