module: refactor modules bootstrap
PR-URL: https://github.com/nodejs/node/pull/29937 Reviewed-By: Myles Borins <myles.borins@gmail.com> Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
This commit is contained in:
parent
1784b7fafa
commit
a6b030d5ac
@ -886,13 +886,13 @@ _isMain_ is **true** when resolving the Node.js application entry point.
|
|||||||
> 1. Throw a _Module Not Found_ error.
|
> 1. Throw a _Module Not Found_ error.
|
||||||
> 1. If _pjson.exports_ is not **null** or **undefined**, then
|
> 1. If _pjson.exports_ is not **null** or **undefined**, then
|
||||||
> 1. If _pjson.exports_ is a String or Array, then
|
> 1. If _pjson.exports_ is a String or Array, then
|
||||||
> 1. Return _PACKAGE_EXPORTS_TARGET_RESOLVE(packageURL, pjson.exports,
|
> 1. Return **PACKAGE_EXPORTS_TARGET_RESOLVE**(_packageURL_,
|
||||||
> "")_.
|
> _pjson.exports_, "")_.
|
||||||
> 1. If _pjson.exports is an Object, then
|
> 1. If _pjson.exports is an Object, then
|
||||||
> 1. If _pjson.exports_ contains a _"."_ property, then
|
> 1. If _pjson.exports_ contains a _"."_ property, then
|
||||||
> 1. Let _mainExport_ be the _"."_ property in _pjson.exports_.
|
> 1. Let _mainExport_ be the _"."_ property in _pjson.exports_.
|
||||||
> 1. Return _PACKAGE_EXPORTS_TARGET_RESOLVE(packageURL, mainExport,
|
> 1. Return **PACKAGE_EXPORTS_TARGET_RESOLVE**(_packageURL_,
|
||||||
> "")_.
|
> _mainExport_, "")_.
|
||||||
> 1. If _pjson.main_ is a String, then
|
> 1. If _pjson.main_ is a String, then
|
||||||
> 1. Let _resolvedMain_ be the URL resolution of _packageURL_, "/", and
|
> 1. Let _resolvedMain_ be the URL resolution of _packageURL_, "/", and
|
||||||
> _pjson.main_.
|
> _pjson.main_.
|
||||||
|
@ -220,7 +220,10 @@ NativeModule.prototype.compileForPublicLoader = function(needToSyncExports) {
|
|||||||
this.compile();
|
this.compile();
|
||||||
if (needToSyncExports) {
|
if (needToSyncExports) {
|
||||||
if (!this.exportKeys) {
|
if (!this.exportKeys) {
|
||||||
this.exportKeys = Object.keys(this.exports);
|
// When using --expose-internals, we do not want to reflect the named
|
||||||
|
// exports from core modules as this can trigger unnecessary getters.
|
||||||
|
const internal = this.id.startsWith('internal/');
|
||||||
|
this.exportKeys = internal ? [] : Object.keys(this.exports);
|
||||||
}
|
}
|
||||||
this.getESMFacade();
|
this.getESMFacade();
|
||||||
this.syncExports();
|
this.syncExports();
|
||||||
|
@ -5,6 +5,7 @@ const { Object, SafeWeakMap } = primordials;
|
|||||||
const { getOptionValue } = require('internal/options');
|
const { getOptionValue } = require('internal/options');
|
||||||
const { Buffer } = require('buffer');
|
const { Buffer } = require('buffer');
|
||||||
const { ERR_MANIFEST_ASSERT_INTEGRITY } = require('internal/errors').codes;
|
const { ERR_MANIFEST_ASSERT_INTEGRITY } = require('internal/errors').codes;
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
function prepareMainThreadExecution(expandArgv1 = false) {
|
function prepareMainThreadExecution(expandArgv1 = false) {
|
||||||
// Patch the process object with legacy properties and normalizations
|
// Patch the process object with legacy properties and normalizations
|
||||||
@ -404,7 +405,6 @@ function initializeESMLoader() {
|
|||||||
'The ESM module loader is experimental.',
|
'The ESM module loader is experimental.',
|
||||||
'ExperimentalWarning', undefined);
|
'ExperimentalWarning', undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
const {
|
const {
|
||||||
setImportModuleDynamicallyCallback,
|
setImportModuleDynamicallyCallback,
|
||||||
setInitializeImportMetaObjectCallback
|
setInitializeImportMetaObjectCallback
|
||||||
@ -414,14 +414,6 @@ function initializeESMLoader() {
|
|||||||
// track of for different ESM modules.
|
// track of for different ESM modules.
|
||||||
setInitializeImportMetaObjectCallback(esm.initializeImportMetaObject);
|
setInitializeImportMetaObjectCallback(esm.initializeImportMetaObject);
|
||||||
setImportModuleDynamicallyCallback(esm.importModuleDynamicallyCallback);
|
setImportModuleDynamicallyCallback(esm.importModuleDynamicallyCallback);
|
||||||
const userLoader = getOptionValue('--experimental-loader');
|
|
||||||
// If --experimental-loader is specified, create a loader with user hooks.
|
|
||||||
// Otherwise create the default loader.
|
|
||||||
if (userLoader) {
|
|
||||||
const { emitExperimentalWarning } = require('internal/util');
|
|
||||||
emitExperimentalWarning('--experimental-loader');
|
|
||||||
}
|
|
||||||
esm.initializeLoader(process.cwd(), userLoader);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -446,11 +438,70 @@ function loadPreloadModules() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function resolveMainPath(main) {
|
||||||
|
const { toRealPath, Module: CJSModule } =
|
||||||
|
require('internal/modules/cjs/loader');
|
||||||
|
|
||||||
|
// Note extension resolution for the main entry point can be deprecated in a
|
||||||
|
// future major.
|
||||||
|
let mainPath = CJSModule._findPath(path.resolve(main), null, true);
|
||||||
|
if (!mainPath)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const preserveSymlinksMain = getOptionValue('--preserve-symlinks-main');
|
||||||
|
if (!preserveSymlinksMain)
|
||||||
|
mainPath = toRealPath(mainPath);
|
||||||
|
|
||||||
|
return mainPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
function shouldUseESMLoader(mainPath) {
|
||||||
|
const experimentalModules = getOptionValue('--experimental-modules');
|
||||||
|
if (!experimentalModules)
|
||||||
|
return false;
|
||||||
|
const userLoader = getOptionValue('--experimental-loader');
|
||||||
|
if (userLoader)
|
||||||
|
return true;
|
||||||
|
// Determine the module format of the main
|
||||||
|
if (mainPath && mainPath.endsWith('.mjs'))
|
||||||
|
return true;
|
||||||
|
if (!mainPath || mainPath.endsWith('.cjs'))
|
||||||
|
return false;
|
||||||
|
const { readPackageScope } = require('internal/modules/cjs/loader');
|
||||||
|
const pkg = readPackageScope(mainPath);
|
||||||
|
return pkg && pkg.data.type === 'module';
|
||||||
|
}
|
||||||
|
|
||||||
|
function runMainESM(mainPath) {
|
||||||
|
const esmLoader = require('internal/process/esm_loader');
|
||||||
|
const { pathToFileURL } = require('internal/url');
|
||||||
|
const { hasUncaughtExceptionCaptureCallback } =
|
||||||
|
require('internal/process/execution');
|
||||||
|
return esmLoader.initializeLoader().then(() => {
|
||||||
|
const main = path.isAbsolute(mainPath) ?
|
||||||
|
pathToFileURL(mainPath).href : mainPath;
|
||||||
|
return esmLoader.ESMLoader.import(main).catch((e) => {
|
||||||
|
if (hasUncaughtExceptionCaptureCallback()) {
|
||||||
|
process._fatalException(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
internalBinding('errors').triggerUncaughtException(
|
||||||
|
e,
|
||||||
|
true /* fromPromise */
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
patchProcessObject,
|
patchProcessObject,
|
||||||
|
resolveMainPath,
|
||||||
|
runMainESM,
|
||||||
setupCoverageHooks,
|
setupCoverageHooks,
|
||||||
setupWarningHandler,
|
setupWarningHandler,
|
||||||
setupDebugEnv,
|
setupDebugEnv,
|
||||||
|
shouldUseESMLoader,
|
||||||
prepareMainThreadExecution,
|
prepareMainThreadExecution,
|
||||||
initializeDeprecations,
|
initializeDeprecations,
|
||||||
initializeESMLoader,
|
initializeESMLoader,
|
||||||
|
@ -10,8 +10,7 @@ const CJSModule = require('internal/modules/cjs/loader').Module;
|
|||||||
|
|
||||||
markBootstrapComplete();
|
markBootstrapComplete();
|
||||||
|
|
||||||
// Note: this actually tries to run the module as a ESM first if
|
// Note: this loads the module through the ESM loader if
|
||||||
// --experimental-modules is on.
|
// --experimental-loader is provided or --experimental-modules is on
|
||||||
// TODO(joyeecheung): can we move that logic to here? Note that this
|
// and the module is determined to be an ES module
|
||||||
// is an undocumented method available via `require('module').runMain`
|
CJSModule.runMain(process.argv[1]);
|
||||||
CJSModule.runMain();
|
|
||||||
|
@ -140,8 +140,9 @@ port.on('message', (message) => {
|
|||||||
const { evalScript } = require('internal/process/execution');
|
const { evalScript } = require('internal/process/execution');
|
||||||
evalScript('[worker eval]', filename);
|
evalScript('[worker eval]', filename);
|
||||||
} else {
|
} else {
|
||||||
process.argv[1] = filename; // script filename
|
// script filename
|
||||||
require('module').runMain();
|
const CJSModule = require('internal/modules/cjs/loader').Module;
|
||||||
|
CJSModule.runMain(process.argv[1] = filename);
|
||||||
}
|
}
|
||||||
} else if (message.type === STDIO_PAYLOAD) {
|
} else if (message.type === STDIO_PAYLOAD) {
|
||||||
const { stream, chunk, encoding } = message;
|
const { stream, chunk, encoding } = message;
|
||||||
|
@ -69,9 +69,14 @@ const {
|
|||||||
ERR_REQUIRE_ESM
|
ERR_REQUIRE_ESM
|
||||||
} = require('internal/errors').codes;
|
} = require('internal/errors').codes;
|
||||||
const { validateString } = require('internal/validators');
|
const { validateString } = require('internal/validators');
|
||||||
|
const {
|
||||||
|
resolveMainPath,
|
||||||
|
shouldUseESMLoader,
|
||||||
|
runMainESM
|
||||||
|
} = require('internal/bootstrap/pre_execution');
|
||||||
const pendingDeprecation = getOptionValue('--pending-deprecation');
|
const pendingDeprecation = getOptionValue('--pending-deprecation');
|
||||||
|
|
||||||
module.exports = { wrapSafe, Module };
|
module.exports = { wrapSafe, Module, toRealPath, readPackageScope };
|
||||||
|
|
||||||
let asyncESM, ModuleJob, ModuleWrap, kInstantiated;
|
let asyncESM, ModuleJob, ModuleWrap, kInstantiated;
|
||||||
|
|
||||||
@ -810,6 +815,10 @@ Module.prototype.load = function(filename) {
|
|||||||
this.paths = Module._nodeModulePaths(path.dirname(filename));
|
this.paths = Module._nodeModulePaths(path.dirname(filename));
|
||||||
|
|
||||||
const extension = findLongestRegisteredExtension(filename);
|
const extension = findLongestRegisteredExtension(filename);
|
||||||
|
// allow .mjs to be overridden
|
||||||
|
if (filename.endsWith('.mjs') && !Module._extensions['.mjs']) {
|
||||||
|
throw new ERR_REQUIRE_ESM(filename);
|
||||||
|
}
|
||||||
Module._extensions[extension](this, filename);
|
Module._extensions[extension](this, filename);
|
||||||
this.loaded = true;
|
this.loaded = true;
|
||||||
|
|
||||||
@ -823,14 +832,19 @@ Module.prototype.load = function(filename) {
|
|||||||
if (module !== undefined && module.module !== undefined) {
|
if (module !== undefined && module.module !== undefined) {
|
||||||
if (module.module.getStatus() >= kInstantiated)
|
if (module.module.getStatus() >= kInstantiated)
|
||||||
module.module.setExport('default', exports);
|
module.module.setExport('default', exports);
|
||||||
} else { // preemptively cache
|
} else {
|
||||||
|
// Preemptively cache
|
||||||
|
// We use a function to defer promise creation for async hooks.
|
||||||
ESMLoader.moduleMap.set(
|
ESMLoader.moduleMap.set(
|
||||||
url,
|
url,
|
||||||
new ModuleJob(ESMLoader, url, () =>
|
// Module job creation will start promises.
|
||||||
|
// We make it a function to lazily trigger those promises
|
||||||
|
// for async hooks compatibility.
|
||||||
|
() => new ModuleJob(ESMLoader, url, () =>
|
||||||
new ModuleWrap(url, undefined, ['default'], function() {
|
new ModuleWrap(url, undefined, ['default'], function() {
|
||||||
this.setExport('default', exports);
|
this.setExport('default', exports);
|
||||||
})
|
})
|
||||||
)
|
, false /* isMain */, false /* inspectBrk */)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -859,7 +873,7 @@ Module.prototype.require = function(id) {
|
|||||||
var resolvedArgv;
|
var resolvedArgv;
|
||||||
let hasPausedEntry = false;
|
let hasPausedEntry = false;
|
||||||
|
|
||||||
function wrapSafe(filename, content) {
|
function wrapSafe(filename, content, cjsModuleInstance) {
|
||||||
if (patched) {
|
if (patched) {
|
||||||
const wrapper = Module.wrap(content);
|
const wrapper = Module.wrap(content);
|
||||||
return vm.runInThisContext(wrapper, {
|
return vm.runInThisContext(wrapper, {
|
||||||
@ -867,7 +881,7 @@ function wrapSafe(filename, content) {
|
|||||||
lineOffset: 0,
|
lineOffset: 0,
|
||||||
displayErrors: true,
|
displayErrors: true,
|
||||||
importModuleDynamically: experimentalModules ? async (specifier) => {
|
importModuleDynamically: experimentalModules ? async (specifier) => {
|
||||||
const loader = await asyncESM.loaderPromise;
|
const loader = asyncESM.ESMLoader;
|
||||||
return loader.import(specifier, normalizeReferrerURL(filename));
|
return loader.import(specifier, normalizeReferrerURL(filename));
|
||||||
} : undefined,
|
} : undefined,
|
||||||
});
|
});
|
||||||
@ -892,9 +906,8 @@ function wrapSafe(filename, content) {
|
|||||||
]
|
]
|
||||||
);
|
);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (experimentalModules) {
|
if (experimentalModules && process.mainModule === cjsModuleInstance)
|
||||||
enrichCJSError(err);
|
enrichCJSError(err);
|
||||||
}
|
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -902,7 +915,7 @@ function wrapSafe(filename, content) {
|
|||||||
const { callbackMap } = internalBinding('module_wrap');
|
const { callbackMap } = internalBinding('module_wrap');
|
||||||
callbackMap.set(compiled.cacheKey, {
|
callbackMap.set(compiled.cacheKey, {
|
||||||
importModuleDynamically: async (specifier) => {
|
importModuleDynamically: async (specifier) => {
|
||||||
const loader = await asyncESM.loaderPromise;
|
const loader = asyncESM.ESMLoader;
|
||||||
return loader.import(specifier, normalizeReferrerURL(filename));
|
return loader.import(specifier, normalizeReferrerURL(filename));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -925,7 +938,7 @@ Module.prototype._compile = function(content, filename) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
maybeCacheSourceMap(filename, content, this);
|
maybeCacheSourceMap(filename, content, this);
|
||||||
const compiledWrapper = wrapSafe(filename, content);
|
const compiledWrapper = wrapSafe(filename, content, this);
|
||||||
|
|
||||||
var inspectorWrapper = null;
|
var inspectorWrapper = null;
|
||||||
if (getOptionValue('--inspect-brk') && process._eval == null) {
|
if (getOptionValue('--inspect-brk') && process._eval == null) {
|
||||||
@ -981,7 +994,11 @@ Module._extensions['.js'] = function(module, filename) {
|
|||||||
'files in that package scope as ES modules.\nInstead rename ' +
|
'files in that package scope as ES modules.\nInstead rename ' +
|
||||||
`${basename} to end in .cjs, change the requiring code to use ` +
|
`${basename} to end in .cjs, change the requiring code to use ` +
|
||||||
'import(), or remove "type": "module" from ' +
|
'import(), or remove "type": "module" from ' +
|
||||||
`${path.resolve(pkg.path, 'package.json')}.`
|
`${path.resolve(pkg.path, 'package.json')}.`,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
true
|
||||||
);
|
);
|
||||||
warnRequireESM = false;
|
warnRequireESM = false;
|
||||||
}
|
}
|
||||||
@ -1024,26 +1041,15 @@ Module._extensions['.node'] = function(module, filename) {
|
|||||||
return process.dlopen(module, path.toNamespacedPath(filename));
|
return process.dlopen(module, path.toNamespacedPath(filename));
|
||||||
};
|
};
|
||||||
|
|
||||||
Module._extensions['.mjs'] = function(module, filename) {
|
|
||||||
throw new ERR_REQUIRE_ESM(filename);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Bootstrap main module.
|
// Bootstrap main module.
|
||||||
Module.runMain = function() {
|
Module.runMain = function(main = process.argv[1]) {
|
||||||
// Load the main module--the command line argument.
|
const resolvedMain = resolveMainPath(main);
|
||||||
if (experimentalModules) {
|
const useESMLoader = shouldUseESMLoader(resolvedMain);
|
||||||
asyncESM.loaderPromise.then((loader) => {
|
if (useESMLoader) {
|
||||||
return loader.import(pathToFileURL(process.argv[1]).href);
|
runMainESM(resolvedMain || main);
|
||||||
})
|
} else {
|
||||||
.catch((e) => {
|
Module._load(main, null, true);
|
||||||
internalBinding('errors').triggerUncaughtException(
|
|
||||||
e,
|
|
||||||
true /* fromPromise */
|
|
||||||
);
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
Module._load(process.argv[1], null, true);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function createRequireFromPath(filename) {
|
function createRequireFromPath(filename) {
|
||||||
@ -1164,7 +1170,7 @@ Module.Module = Module;
|
|||||||
|
|
||||||
// We have to load the esm things after module.exports!
|
// We have to load the esm things after module.exports!
|
||||||
if (experimentalModules) {
|
if (experimentalModules) {
|
||||||
asyncESM = require('internal/process/esm_loader');
|
|
||||||
ModuleJob = require('internal/modules/esm/module_job');
|
ModuleJob = require('internal/modules/esm/module_job');
|
||||||
|
asyncESM = require('internal/process/esm_loader');
|
||||||
({ ModuleWrap, kInstantiated } = internalBinding('module_wrap'));
|
({ ModuleWrap, kInstantiated } = internalBinding('module_wrap'));
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ const createDynamicModule = require(
|
|||||||
'internal/modules/esm/create_dynamic_module');
|
'internal/modules/esm/create_dynamic_module');
|
||||||
const { translators } = require('internal/modules/esm/translators');
|
const { translators } = require('internal/modules/esm/translators');
|
||||||
const { ModuleWrap } = internalBinding('module_wrap');
|
const { ModuleWrap } = internalBinding('module_wrap');
|
||||||
|
const { getOptionValue } = require('internal/options');
|
||||||
|
|
||||||
const debug = require('internal/util/debuglog').debuglog('esm');
|
const debug = require('internal/util/debuglog').debuglog('esm');
|
||||||
|
|
||||||
@ -118,7 +119,7 @@ class Loader {
|
|||||||
url = pathToFileURL(`${process.cwd()}/[eval${++this.evalIndex}]`).href
|
url = pathToFileURL(`${process.cwd()}/[eval${++this.evalIndex}]`).href
|
||||||
) {
|
) {
|
||||||
const evalInstance = (url) => new ModuleWrap(url, undefined, source, 0, 0);
|
const evalInstance = (url) => new ModuleWrap(url, undefined, source, 0, 0);
|
||||||
const job = new ModuleJob(this, url, evalInstance, false);
|
const job = new ModuleJob(this, url, evalInstance, false, false);
|
||||||
this.moduleMap.set(url, job);
|
this.moduleMap.set(url, job);
|
||||||
const { module, result } = await job.run();
|
const { module, result } = await job.run();
|
||||||
return {
|
return {
|
||||||
@ -146,6 +147,9 @@ class Loader {
|
|||||||
async getModuleJob(specifier, parentURL) {
|
async getModuleJob(specifier, parentURL) {
|
||||||
const { url, format } = await this.resolve(specifier, parentURL);
|
const { url, format } = await this.resolve(specifier, parentURL);
|
||||||
let job = this.moduleMap.get(url);
|
let job = this.moduleMap.get(url);
|
||||||
|
// CommonJS will set functions for lazy job evaluation.
|
||||||
|
if (typeof job === 'function')
|
||||||
|
this.moduleMap.set(url, job = job());
|
||||||
if (job !== undefined)
|
if (job !== undefined)
|
||||||
return job;
|
return job;
|
||||||
|
|
||||||
@ -169,7 +173,10 @@ class Loader {
|
|||||||
loaderInstance = translators.get(format);
|
loaderInstance = translators.get(format);
|
||||||
}
|
}
|
||||||
|
|
||||||
job = new ModuleJob(this, url, loaderInstance, parentURL === undefined);
|
const inspectBrk = parentURL === undefined &&
|
||||||
|
format === 'module' && getOptionValue('--inspect-brk');
|
||||||
|
job = new ModuleJob(this, url, loaderInstance, parentURL === undefined,
|
||||||
|
inspectBrk);
|
||||||
this.moduleMap.set(url, job);
|
this.moduleMap.set(url, job);
|
||||||
return job;
|
return job;
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,6 @@ const {
|
|||||||
const { ModuleWrap } = internalBinding('module_wrap');
|
const { ModuleWrap } = internalBinding('module_wrap');
|
||||||
|
|
||||||
const { decorateErrorStack } = require('internal/util');
|
const { decorateErrorStack } = require('internal/util');
|
||||||
const { getOptionValue } = require('internal/options');
|
|
||||||
const assert = require('internal/assert');
|
const assert = require('internal/assert');
|
||||||
const resolvedPromise = SafePromise.resolve();
|
const resolvedPromise = SafePromise.resolve();
|
||||||
|
|
||||||
@ -22,9 +21,10 @@ let hasPausedEntry = false;
|
|||||||
class ModuleJob {
|
class ModuleJob {
|
||||||
// `loader` is the Loader instance used for loading dependencies.
|
// `loader` is the Loader instance used for loading dependencies.
|
||||||
// `moduleProvider` is a function
|
// `moduleProvider` is a function
|
||||||
constructor(loader, url, moduleProvider, isMain) {
|
constructor(loader, url, moduleProvider, isMain, inspectBrk) {
|
||||||
this.loader = loader;
|
this.loader = loader;
|
||||||
this.isMain = isMain;
|
this.isMain = isMain;
|
||||||
|
this.inspectBrk = inspectBrk;
|
||||||
|
|
||||||
// This is a Promise<{ module, reflect }>, whose fields will be copied
|
// This is a Promise<{ module, reflect }>, whose fields will be copied
|
||||||
// onto `this` by `link()` below once it has been resolved.
|
// onto `this` by `link()` below once it has been resolved.
|
||||||
@ -83,12 +83,12 @@ class ModuleJob {
|
|||||||
};
|
};
|
||||||
await addJobsToDependencyGraph(this);
|
await addJobsToDependencyGraph(this);
|
||||||
try {
|
try {
|
||||||
if (!hasPausedEntry && this.isMain && getOptionValue('--inspect-brk')) {
|
if (!hasPausedEntry && this.inspectBrk) {
|
||||||
hasPausedEntry = true;
|
hasPausedEntry = true;
|
||||||
const initWrapper = internalBinding('inspector').callAndPauseOnStart;
|
const initWrapper = internalBinding('inspector').callAndPauseOnStart;
|
||||||
initWrapper(this.module.instantiate, this.module);
|
initWrapper(this.module.instantiate, this.module);
|
||||||
} else {
|
} else {
|
||||||
this.module.instantiate();
|
this.module.instantiate(true);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
decorateErrorStack(e);
|
decorateErrorStack(e);
|
||||||
|
@ -16,7 +16,8 @@ class ModuleMap extends SafeMap {
|
|||||||
}
|
}
|
||||||
set(url, job) {
|
set(url, job) {
|
||||||
validateString(url, 'url');
|
validateString(url, 'url');
|
||||||
if (job instanceof ModuleJob !== true) {
|
if (job instanceof ModuleJob !== true &&
|
||||||
|
typeof job !== 'function') {
|
||||||
throw new ERR_INVALID_ARG_TYPE('job', 'ModuleJob', job);
|
throw new ERR_INVALID_ARG_TYPE('job', 'ModuleJob', job);
|
||||||
}
|
}
|
||||||
debug(`Storing ${url} in ModuleMap`);
|
debug(`Storing ${url} in ModuleMap`);
|
||||||
|
@ -23,7 +23,6 @@ const fs = require('fs');
|
|||||||
const { fileURLToPath, URL } = require('url');
|
const { fileURLToPath, URL } = require('url');
|
||||||
const { debuglog } = require('internal/util/debuglog');
|
const { debuglog } = require('internal/util/debuglog');
|
||||||
const { promisify } = require('internal/util');
|
const { promisify } = require('internal/util');
|
||||||
const esmLoader = require('internal/process/esm_loader');
|
|
||||||
const {
|
const {
|
||||||
ERR_INVALID_URL,
|
ERR_INVALID_URL,
|
||||||
ERR_INVALID_URL_SCHEME,
|
ERR_INVALID_URL_SCHEME,
|
||||||
@ -69,9 +68,12 @@ function initializeImportMeta(meta, { url }) {
|
|||||||
meta.url = url;
|
meta.url = url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let esmLoader;
|
||||||
async function importModuleDynamically(specifier, { url }) {
|
async function importModuleDynamically(specifier, { url }) {
|
||||||
const loader = await esmLoader.loaderPromise;
|
if (!esmLoader) {
|
||||||
return loader.import(specifier, url);
|
esmLoader = require('internal/process/esm_loader');
|
||||||
|
}
|
||||||
|
return esmLoader.ESMLoader.import(specifier, url);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Strategy for loading a standard JavaScript module
|
// Strategy for loading a standard JavaScript module
|
||||||
|
@ -3,12 +3,14 @@
|
|||||||
const {
|
const {
|
||||||
ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING,
|
ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING,
|
||||||
} = require('internal/errors').codes;
|
} = require('internal/errors').codes;
|
||||||
|
const assert = require('internal/assert');
|
||||||
const { Loader } = require('internal/modules/esm/loader');
|
const { Loader } = require('internal/modules/esm/loader');
|
||||||
const { pathToFileURL } = require('internal/url');
|
const { pathToFileURL } = require('internal/url');
|
||||||
const {
|
const {
|
||||||
getModuleFromWrap,
|
getModuleFromWrap,
|
||||||
} = require('internal/vm/module');
|
} = require('internal/vm/module');
|
||||||
|
const { getOptionValue } = require('internal/options');
|
||||||
|
const userLoader = getOptionValue('--experimental-loader');
|
||||||
|
|
||||||
exports.initializeImportMetaObject = function(wrap, meta) {
|
exports.initializeImportMetaObject = function(wrap, meta) {
|
||||||
const { callbackMap } = internalBinding('module_wrap');
|
const { callbackMap } = internalBinding('module_wrap');
|
||||||
@ -21,6 +23,7 @@ exports.initializeImportMetaObject = function(wrap, meta) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
exports.importModuleDynamicallyCallback = async function(wrap, specifier) {
|
exports.importModuleDynamicallyCallback = async function(wrap, specifier) {
|
||||||
|
assert(calledInitialize === true || !userLoader);
|
||||||
const { callbackMap } = internalBinding('module_wrap');
|
const { callbackMap } = internalBinding('module_wrap');
|
||||||
if (callbackMap.has(wrap)) {
|
if (callbackMap.has(wrap)) {
|
||||||
const { importModuleDynamically } = callbackMap.get(wrap);
|
const { importModuleDynamically } = callbackMap.get(wrap);
|
||||||
@ -32,24 +35,31 @@ exports.importModuleDynamicallyCallback = async function(wrap, specifier) {
|
|||||||
throw new ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING();
|
throw new ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING();
|
||||||
};
|
};
|
||||||
|
|
||||||
let loaderResolve;
|
let ESMLoader = new Loader();
|
||||||
exports.loaderPromise = new Promise((resolve) => loaderResolve = resolve);
|
exports.ESMLoader = ESMLoader;
|
||||||
|
|
||||||
exports.ESMLoader = undefined;
|
let calledInitialize = false;
|
||||||
|
exports.initializeLoader = initializeLoader;
|
||||||
exports.initializeLoader = function(cwd, userLoader) {
|
async function initializeLoader() {
|
||||||
let ESMLoader = new Loader();
|
assert(calledInitialize === false);
|
||||||
const loaderPromise = (async () => {
|
calledInitialize = true;
|
||||||
if (userLoader) {
|
if (!userLoader)
|
||||||
const hooks = await ESMLoader.import(
|
return;
|
||||||
userLoader, pathToFileURL(`${cwd}/`).href);
|
let cwd;
|
||||||
|
try {
|
||||||
|
cwd = process.cwd() + '/';
|
||||||
|
} catch {
|
||||||
|
cwd = 'file:///';
|
||||||
|
}
|
||||||
|
// If --experimental-loader is specified, create a loader with user hooks.
|
||||||
|
// Otherwise create the default loader.
|
||||||
|
const { emitExperimentalWarning } = require('internal/util');
|
||||||
|
emitExperimentalWarning('--experimental-loader');
|
||||||
|
return (async () => {
|
||||||
|
const hooks =
|
||||||
|
await ESMLoader.import(userLoader, pathToFileURL(cwd).href);
|
||||||
ESMLoader = new Loader();
|
ESMLoader = new Loader();
|
||||||
ESMLoader.hook(hooks);
|
ESMLoader.hook(hooks);
|
||||||
exports.ESMLoader = ESMLoader;
|
return exports.ESMLoader = ESMLoader;
|
||||||
}
|
|
||||||
return ESMLoader;
|
|
||||||
})();
|
})();
|
||||||
loaderResolve(loaderPromise);
|
}
|
||||||
|
|
||||||
exports.ESMLoader = ESMLoader;
|
|
||||||
};
|
|
||||||
|
@ -39,7 +39,7 @@ function evalModule(source, print) {
|
|||||||
const { log, error } = require('internal/console/global');
|
const { log, error } = require('internal/console/global');
|
||||||
const { decorateErrorStack } = require('internal/util');
|
const { decorateErrorStack } = require('internal/util');
|
||||||
const asyncESM = require('internal/process/esm_loader');
|
const asyncESM = require('internal/process/esm_loader');
|
||||||
asyncESM.loaderPromise.then(async (loader) => {
|
Promise.resolve(asyncESM.ESMLoader).then(async (loader) => {
|
||||||
const { result } = await loader.eval(source);
|
const { result } = await loader.eval(source);
|
||||||
if (print) {
|
if (print) {
|
||||||
log(result);
|
log(result);
|
||||||
|
15
lib/repl.js
15
lib/repl.js
@ -99,6 +99,7 @@ const {
|
|||||||
} = internalBinding('contextify');
|
} = internalBinding('contextify');
|
||||||
|
|
||||||
const history = require('internal/repl/history');
|
const history = require('internal/repl/history');
|
||||||
|
const { setImmediate } = require('timers');
|
||||||
|
|
||||||
// Lazy-loaded.
|
// Lazy-loaded.
|
||||||
let processTopLevelAwait;
|
let processTopLevelAwait;
|
||||||
@ -338,11 +339,9 @@ function REPLServer(prompt,
|
|||||||
script = vm.createScript(code, {
|
script = vm.createScript(code, {
|
||||||
filename: file,
|
filename: file,
|
||||||
displayErrors: true,
|
displayErrors: true,
|
||||||
importModuleDynamically: experimentalModules ?
|
importModuleDynamically: experimentalModules ? async (specifier) => {
|
||||||
async (specifier) => {
|
return asyncESM.ESMLoader.import(specifier, pwd);
|
||||||
return (await asyncESM.loaderPromise).import(specifier, pwd);
|
} : undefined
|
||||||
} :
|
|
||||||
undefined
|
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debug('parse error %j', code, e);
|
debug('parse error %j', code, e);
|
||||||
@ -1080,7 +1079,11 @@ function complete(line, callback) {
|
|||||||
// All this is only profitable if the nested REPL does not have a
|
// All this is only profitable if the nested REPL does not have a
|
||||||
// bufferedCommand.
|
// bufferedCommand.
|
||||||
if (!magic[kBufferedCommandSymbol]) {
|
if (!magic[kBufferedCommandSymbol]) {
|
||||||
magic._domain.on('error', (err) => { throw err; });
|
magic._domain.on('error', (err) => {
|
||||||
|
setImmediate(() => {
|
||||||
|
throw err;
|
||||||
|
});
|
||||||
|
});
|
||||||
return magic.complete(line, callback);
|
return magic.complete(line, callback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
// Flags: --expose-internals
|
// Flags: --expose-internals --experimental-modules
|
||||||
|
|
||||||
// This test ensures that the type checking of ModuleMap throws
|
// This test ensures that the type checking of ModuleMap throws
|
||||||
// errors appropriately
|
// errors appropriately
|
||||||
|
@ -15,11 +15,6 @@ const child = spawn(process.execPath, [
|
|||||||
entry
|
entry
|
||||||
]);
|
]);
|
||||||
|
|
||||||
let stderr = '';
|
|
||||||
child.stderr.setEncoding('utf8');
|
|
||||||
child.stderr.on('data', (data) => {
|
|
||||||
stderr += data;
|
|
||||||
});
|
|
||||||
let stdout = '';
|
let stdout = '';
|
||||||
child.stdout.setEncoding('utf8');
|
child.stdout.setEncoding('utf8');
|
||||||
child.stdout.on('data', (data) => {
|
child.stdout.on('data', (data) => {
|
||||||
@ -29,6 +24,4 @@ child.on('close', common.mustCall((code, signal) => {
|
|||||||
assert.strictEqual(code, 0);
|
assert.strictEqual(code, 0);
|
||||||
assert.strictEqual(signal, null);
|
assert.strictEqual(signal, null);
|
||||||
assert.strictEqual(stdout, 'executed\n');
|
assert.strictEqual(stdout, 'executed\n');
|
||||||
assert.strictEqual(stderr, `(node:${child.pid}) ` +
|
|
||||||
'ExperimentalWarning: The ESM module loader is experimental.\n');
|
|
||||||
}));
|
}));
|
||||||
|
@ -92,7 +92,6 @@ if (common.isMainThread) {
|
|||||||
expectedModules.add('NativeModule internal/streams/state');
|
expectedModules.add('NativeModule internal/streams/state');
|
||||||
expectedModules.add('NativeModule internal/worker');
|
expectedModules.add('NativeModule internal/worker');
|
||||||
expectedModules.add('NativeModule internal/worker/io');
|
expectedModules.add('NativeModule internal/worker/io');
|
||||||
expectedModules.add('NativeModule module');
|
|
||||||
expectedModules.add('NativeModule stream');
|
expectedModules.add('NativeModule stream');
|
||||||
expectedModules.add('NativeModule worker_threads');
|
expectedModules.add('NativeModule worker_threads');
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ const ModuleMap = require('internal/modules/esm/module_map');
|
|||||||
code: 'ERR_INVALID_ARG_TYPE',
|
code: 'ERR_INVALID_ARG_TYPE',
|
||||||
type: TypeError,
|
type: TypeError,
|
||||||
message: /^The "url" argument must be of type string/
|
message: /^The "url" argument must be of type string/
|
||||||
}, 15);
|
}, 12);
|
||||||
|
|
||||||
const moduleMap = new ModuleMap();
|
const moduleMap = new ModuleMap();
|
||||||
|
|
||||||
@ -21,7 +21,7 @@ const ModuleMap = require('internal/modules/esm/module_map');
|
|||||||
// but I think it's useless, and was not simple to mock...
|
// but I think it's useless, and was not simple to mock...
|
||||||
const job = undefined;
|
const job = undefined;
|
||||||
|
|
||||||
[{}, [], true, 1, () => {}].forEach((value) => {
|
[{}, [], true, 1].forEach((value) => {
|
||||||
assert.throws(() => moduleMap.get(value), errorReg);
|
assert.throws(() => moduleMap.get(value), errorReg);
|
||||||
assert.throws(() => moduleMap.has(value), errorReg);
|
assert.throws(() => moduleMap.has(value), errorReg);
|
||||||
assert.throws(() => moduleMap.set(value, job), errorReg);
|
assert.throws(() => moduleMap.set(value, job), errorReg);
|
||||||
@ -34,11 +34,11 @@ const ModuleMap = require('internal/modules/esm/module_map');
|
|||||||
code: 'ERR_INVALID_ARG_TYPE',
|
code: 'ERR_INVALID_ARG_TYPE',
|
||||||
type: TypeError,
|
type: TypeError,
|
||||||
message: /^The "job" argument must be of type ModuleJob/
|
message: /^The "job" argument must be of type ModuleJob/
|
||||||
}, 5);
|
}, 4);
|
||||||
|
|
||||||
const moduleMap = new ModuleMap();
|
const moduleMap = new ModuleMap();
|
||||||
|
|
||||||
[{}, [], true, 1, () => {}].forEach((value) => {
|
[{}, [], true, 1].forEach((value) => {
|
||||||
assert.throws(() => moduleMap.set('', value), errorReg);
|
assert.throws(() => moduleMap.set('', value), errorReg);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user