esm,loader: tidy ESMLoader internals

PR-URL: https://github.com/nodejs/node/pull/44701
Reviewed-By: Geoffrey Booth <webadmin@geoffreybooth.com>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
This commit is contained in:
Jacob Smith
2022-09-19 22:55:09 +02:00
committed by GitHub
parent e62e99d983
commit e2e5b2eaf1
3 changed files with 73 additions and 75 deletions

View File

@@ -1,8 +1,6 @@
'use strict';
const {
RegExpPrototypeExec,
ObjectAssign,
ObjectCreate,
ObjectPrototypeHasOwnProperty,
PromisePrototypeThen,
PromiseResolve,
@@ -25,13 +23,14 @@ const { getPackageType, getPackageScopeConfig } = require('internal/modules/esm/
const { URL, fileURLToPath } = require('internal/url');
const { ERR_UNKNOWN_FILE_EXTENSION } = require('internal/errors').codes;
const protocolHandlers = ObjectAssign(ObjectCreate(null), {
const protocolHandlers = {
'__proto__': null,
'data:': getDataProtocolModuleFormat,
'file:': getFileProtocolModuleFormat,
'http:': getHttpProtocolModuleFormat,
'https:': getHttpProtocolModuleFormat,
'node:'() { return 'builtin'; },
});
};
/**
* @param {URL} parsed

View File

@@ -179,39 +179,38 @@ function nextHookFactory(chain, meta, { validateArgs, validateOutput }) {
* the main module and everything in its dependency graph.
*/
class ESMLoader {
/**
* Prior to ESM loading. These are called once before any modules are started.
* @private
* @property {KeyedHook[]} globalPreloaders Last-in-first-out
* list of preload hooks.
*/
#globalPreloaders = [];
#hooks = {
/**
* 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 2 of 2 in ESM loading.
* @private
* @property {KeyedHook[]} loaders Last-in-first-out
* collection of loader hooks.
*/
#loaders = [
{
fn: defaultLoad,
url: 'node:internal/modules/esm/load',
},
];
/**
* Phase 2 of 2 in ESM loading (phase 1 is below).
* @private
* @property {KeyedHook[]} load Last-in-first-out collection of loader hooks.
*/
load: [
{
fn: defaultLoad,
url: 'node:internal/modules/esm/load',
},
],
/**
* Phase 1 of 2 in ESM loading.
* @private
* @property {KeyedHook[]} resolvers Last-in-first-out
* collection of resolver hooks.
*/
#resolvers = [
{
fn: defaultResolve,
url: 'node:internal/modules/esm/resolve',
},
];
/**
* Phase 1 of 2 in ESM loading.
* @private
* @property {KeyedHook[]} resolve Last-in-first-out collection of resolve hooks.
*/
resolve: [
{
fn: defaultResolve,
url: 'node:internal/modules/esm/resolve',
},
],
};
#importMetaInitializer = initializeImportMeta;
@@ -305,13 +304,13 @@ class ESMLoader {
);
if (globalPreload) {
acceptedHooks.globalPreloader = globalPreload;
acceptedHooks.globalPreload = globalPreload;
}
if (resolve) {
acceptedHooks.resolver = resolve;
acceptedHooks.resolve = resolve;
}
if (load) {
acceptedHooks.loader = load;
acceptedHooks.load = load;
}
return acceptedHooks;
@@ -333,34 +332,34 @@ class ESMLoader {
url,
} = customLoaders[i];
const {
globalPreloader,
resolver,
loader,
globalPreload,
resolve,
load,
} = ESMLoader.pluckHooks(exports);
if (globalPreloader) {
if (globalPreload) {
ArrayPrototypePush(
this.#globalPreloaders,
this.#hooks.globalPreload,
{
fn: globalPreloader,
fn: globalPreload,
url,
},
);
}
if (resolver) {
if (resolve) {
ArrayPrototypePush(
this.#resolvers,
this.#hooks.resolve,
{
fn: resolver,
fn: resolve,
url,
},
);
}
if (loader) {
if (load) {
ArrayPrototypePush(
this.#loaders,
this.#hooks.load,
{
fn: loader,
fn: load,
url,
},
);
@@ -411,14 +410,14 @@ class ESMLoader {
async getModuleJob(specifier, parentURL, importAssertions) {
let importAssertionsForResolve;
// By default, `this.#loaders` contains just the Node default load hook
if (this.#loaders.length !== 1) {
// By default, `this.#hooks.load` contains just the Node default load hook
if (this.#hooks.load.length !== 1) {
// We can skip cloning if there are no user-provided loaders because
// the Node.js default resolve hook does not use import assertions.
importAssertionsForResolve = ObjectAssign(
ObjectCreate(null),
importAssertions,
);
importAssertionsForResolve = {
__proto__: null,
...importAssertions,
};
}
const { format, url } =
@@ -533,11 +532,11 @@ class ESMLoader {
if (!wasArr) { return namespaces[0]; } // We can skip the pairing below
for (let i = 0; i < count; i++) {
const namespace = ObjectCreate(null);
namespace.url = specifiers[i];
namespace.exports = namespaces[i];
namespaces[i] = namespace;
namespaces[i] = {
__proto__: null,
url: specifiers[i],
exports: namespaces[i],
};
}
return namespaces;
@@ -555,7 +554,7 @@ class ESMLoader {
* @returns {{ format: ModuleFormat, source: ModuleSource }}
*/
async load(url, context = {}) {
const chain = this.#loaders;
const chain = this.#hooks.load;
const meta = {
chainFinished: null,
context,
@@ -684,7 +683,7 @@ class ESMLoader {
}
preload() {
for (let i = this.#globalPreloaders.length - 1; i >= 0; i--) {
for (let i = this.#hooks.globalPreload.length - 1; i >= 0; i--) {
const channel = new MessageChannel();
const {
port1: insidePreload,
@@ -695,19 +694,19 @@ class ESMLoader {
insideLoader.unref();
const {
fn: preloader,
fn: preload,
url: specifier,
} = this.#globalPreloaders[i];
} = this.#hooks.globalPreload[i];
const preload = preloader({
const preloaded = preload({
port: insideLoader,
});
if (preload == null) { return; }
if (preloaded == null) { return; }
const hookErrIdentifier = `${specifier} globalPreload`;
if (typeof preload !== 'string') { // [2]
if (typeof preloaded !== 'string') { // [2]
throw new ERR_INVALID_RETURN_VALUE(
'a string',
hookErrIdentifier,
@@ -716,7 +715,7 @@ class ESMLoader {
}
const { compileFunction } = require('vm');
const preloadInit = compileFunction(
preload,
preloaded,
['getBuiltin', 'port', 'setImportMetaCallback'],
{
filename: '<preload>',
@@ -789,7 +788,7 @@ class ESMLoader {
async resolve(
originalSpecifier,
parentURL,
importAssertions = ObjectCreate(null)
importAssertions = ObjectCreate(null),
) {
const isMain = parentURL === undefined;
@@ -804,7 +803,7 @@ class ESMLoader {
parentURL,
);
}
const chain = this.#resolvers;
const chain = this.#hooks.resolve;
const context = {
conditions: DEFAULT_CONDITIONS,
importAssertions,

View File

@@ -12,10 +12,10 @@ const { ESMLoader } = esmLoaderModule;
const esmLoader = new ESMLoader();
const originalSpecifier = 'foo/bar';
const importAssertions = Object.assign(
Object.create(null),
{ type: 'json' },
);
const importAssertions = {
__proto__: null,
type: 'json',
};
const parentURL = 'file:///entrypoint.js';
const resolvedURL = 'file:///foo/bar.js';
const suggestedFormat = 'test';