mirror of
https://github.com/nodejs/node.git
synced 2025-05-12 20:54:38 +00:00

PR-URL: https://github.com/nodejs/node/pull/43942 Fixes: https://github.com/nodejs/node/issues/40110 Reviewed-By: Geoffrey Booth <webadmin@geoffreybooth.com> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Jacob Smith <jacob@frende.me> Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
114 lines
3.3 KiB
JavaScript
114 lines
3.3 KiB
JavaScript
'use strict';
|
|
|
|
const {
|
|
ArrayIsArray,
|
|
ObjectCreate,
|
|
} = primordials;
|
|
|
|
const {
|
|
ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING,
|
|
} = require('internal/errors').codes;
|
|
const { ESMLoader } = require('internal/modules/esm/loader');
|
|
const {
|
|
hasUncaughtExceptionCaptureCallback,
|
|
} = require('internal/process/execution');
|
|
const { pathToFileURL } = require('internal/url');
|
|
const {
|
|
getModuleFromWrap,
|
|
} = require('internal/vm/module');
|
|
|
|
exports.initializeImportMetaObject = function(wrap, meta) {
|
|
const { callbackMap } = internalBinding('module_wrap');
|
|
if (callbackMap.has(wrap)) {
|
|
const { initializeImportMeta } = callbackMap.get(wrap);
|
|
if (initializeImportMeta !== undefined) {
|
|
initializeImportMeta(meta, getModuleFromWrap(wrap) || wrap);
|
|
}
|
|
}
|
|
};
|
|
|
|
exports.importModuleDynamicallyCallback =
|
|
async function importModuleDynamicallyCallback(wrap, specifier, assertions) {
|
|
const { callbackMap } = internalBinding('module_wrap');
|
|
if (callbackMap.has(wrap)) {
|
|
const { importModuleDynamically } = callbackMap.get(wrap);
|
|
if (importModuleDynamically !== undefined) {
|
|
return importModuleDynamically(
|
|
specifier, getModuleFromWrap(wrap) || wrap, assertions);
|
|
}
|
|
}
|
|
throw new ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING();
|
|
};
|
|
|
|
const esmLoader = new ESMLoader();
|
|
exports.esmLoader = esmLoader;
|
|
|
|
// Module.runMain() causes loadESM() to re-run (which it should do); however, this should NOT cause
|
|
// ESM to be re-initialised; doing so causes duplicate custom loaders to be added to the public
|
|
// esmLoader.
|
|
let isESMInitialized = false;
|
|
|
|
/**
|
|
* Causes side-effects: user-defined loader hooks are added to esmLoader.
|
|
* @returns {void}
|
|
*/
|
|
async function initializeLoader() {
|
|
if (isESMInitialized) { return; }
|
|
|
|
const { getOptionValue } = require('internal/options');
|
|
const customLoaders = getOptionValue('--experimental-loader');
|
|
const preloadModules = getOptionValue('--import');
|
|
const loaders = await loadModulesInIsolation(customLoaders);
|
|
|
|
// Hooks must then be added to external/public loader
|
|
// (so they're triggered in userland)
|
|
esmLoader.addCustomLoaders(loaders);
|
|
|
|
// Preload after loaders are added so they can be used
|
|
if (preloadModules?.length) {
|
|
await loadModulesInIsolation(preloadModules, loaders);
|
|
}
|
|
|
|
isESMInitialized = true;
|
|
}
|
|
|
|
function loadModulesInIsolation(specifiers, loaders = []) {
|
|
if (!ArrayIsArray(specifiers) || specifiers.length === 0) { return; }
|
|
|
|
let cwd;
|
|
try {
|
|
cwd = process.cwd() + '/';
|
|
} catch {
|
|
cwd = 'file:///';
|
|
}
|
|
|
|
// A separate loader instance is necessary to avoid cross-contamination
|
|
// between internal Node.js and userland. For example, a module with internal
|
|
// state (such as a counter) should be independent.
|
|
const internalEsmLoader = new ESMLoader();
|
|
internalEsmLoader.addCustomLoaders(loaders);
|
|
|
|
// Importation must be handled by internal loader to avoid poluting userland
|
|
return internalEsmLoader.import(
|
|
specifiers,
|
|
pathToFileURL(cwd).href,
|
|
ObjectCreate(null),
|
|
);
|
|
}
|
|
|
|
exports.loadESM = async function loadESM(callback) {
|
|
try {
|
|
await initializeLoader();
|
|
await callback(esmLoader);
|
|
} catch (err) {
|
|
if (hasUncaughtExceptionCaptureCallback()) {
|
|
process._fatalException(err);
|
|
return;
|
|
}
|
|
internalBinding('errors').triggerUncaughtException(
|
|
err,
|
|
true /* fromPromise */
|
|
);
|
|
}
|
|
};
|