Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

esm: remove CLI flag limitation to programmatic registration #48439

Closed
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 14 additions & 8 deletions lib/internal/modules/esm/initialize_import_meta.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,26 @@

const { getOptionValue } = require('internal/options');
const experimentalImportMetaResolve = getOptionValue('--experimental-import-meta-resolve');
let debug = require('internal/util/debuglog').debuglog('esm', (fn) => {
debug = fn;
});

/**
* Generate a function to be used as import.meta.resolve for a particular module.
* @param {string} defaultParentUrl The default base to use for resolution
* @param {typeof import('./loader.js').ModuleLoader} loader Reference to the current module loader
* @returns {(specifier: string, parentUrl?: string) => string} Function to assign to import.meta.resolve
*/
function createImportMetaResolve(defaultParentUrl, loader) {
function createImportMetaResolve(defaultParentUrl) {
debug('createImportMetaResolve(): %o', { defaultParentUrl });

return function resolve(specifier, parentUrl = defaultParentUrl) {
const moduleLoader = require('internal/process/esm_loader').esmLoader;
let url;

debug('import.meta.resolve(%o) %s', { specifier, parentUrl }, moduleLoader.constructor.name);

try {
({ url } = loader.resolve(specifier, parentUrl));
({ url } = moduleLoader.resolve(specifier, parentUrl));
} catch (error) {
if (error?.code === 'ERR_UNSUPPORTED_DIR_IMPORT') {
({ url } = error);
Expand All @@ -31,15 +38,14 @@ function createImportMetaResolve(defaultParentUrl, loader) {
* Create the `import.meta` object for a module.
* @param {object} meta
* @param {{url: string}} context
* @param {typeof import('./loader.js').ModuleLoader} loader Reference to the current module loader
* @returns {{url: string, resolve?: Function}}
*/
function initializeImportMeta(meta, context, loader) {
const { url } = context;
function initializeImportMeta(meta, { url }) {
debug('initializeImportMeta for %s', url);

// Alphabetical
if (experimentalImportMetaResolve && loader.loaderType !== 'internal') {
meta.resolve = createImportMetaResolve(url, loader);
if (experimentalImportMetaResolve) {
meta.resolve = createImportMetaResolve(url);
}

meta.url = url;
Expand Down
18 changes: 7 additions & 11 deletions lib/internal/modules/esm/loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ const { emitExperimentalWarning, kEmptyObject } = require('internal/util');
const {
getDefaultConditions,
} = require('internal/modules/esm/utils');
let defaultResolve, defaultLoad, importMetaInitializer;
let defaultResolve;
let defaultLoad;
let debug = require('internal/util/debuglog').debuglog('esm', (fn) => {
debug = fn;
});
Expand Down Expand Up @@ -138,7 +139,7 @@ class DefaultModuleLoader {
importAssertions = resolveResult.importAssertions,
) {
const { url, format } = resolveResult;
debug('getModuleJob', { url, format, parentURL, importAssertions, moduleMap: this.moduleMap });
debug('getJobFromResolveResult:', { [url]: { format, moduleMap: this.moduleMap } });
let job = this.moduleMap.get(url, importAssertions.type);

// CommonJS will set functions for lazy job evaluation.
Expand Down Expand Up @@ -186,11 +187,12 @@ debug('getModuleJob', { url, format, parentURL, importAssertions, moduleMap: thi
}

const isMain = parentURL === undefined;
debug('#createModuleJob', { url, finalFormat, responseURL, source });
const moduleWrapper = FunctionPrototypeCall(translator, this, responseURL, source, isMain);

const ModuleJob = require('internal/modules/esm/module_job');
const job = new ModuleJob(
url,
responseURL,
moduleWrapper,
importAssertions,
isMain,
Expand Down Expand Up @@ -258,12 +260,6 @@ debug('getModuleJob', { url, format, parentURL, importAssertions, moduleMap: thi
require('internal/modules/esm/load').throwUnknownModuleFormat(url, format);
}
}

importMetaInitialize(meta, context) {
importMetaInitializer ??= require('internal/modules/esm/initialize_import_meta').initializeImportMeta;
meta = importMetaInitializer(meta, context, this);
return meta;
}
}
ObjectSetPrototypeOf(DefaultModuleLoader.prototype, null);

Expand Down Expand Up @@ -316,12 +312,12 @@ class CustomizedModuleLoader extends DefaultModuleLoader {

async #getModuleJob(specifier, parentURL, importAssertions) {
const resolveResult = await hooksProxy.makeAsyncRequest('resolve', specifier, parentURL, importAssertions);

debug('#getModuleJob', { [specifier]: resolveResult })
return this.getJobFromResolveResult(resolveResult, parentURL, importAssertions);
}
getModuleJob(specifier, parentURL, importAssertions) {
const jobPromise = this.#getModuleJob(specifier, parentURL, importAssertions);

debug('getModuleJob', { [specifier]: jobPromise })
return {
run() {
return PromisePrototypeThen(jobPromise, (job) => job.run());
Expand Down
35 changes: 14 additions & 21 deletions lib/internal/modules/esm/module_job.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ const {
} = primordials;

const { ModuleWrap } = internalBinding('module_wrap');
const { setCallbackForWrap } = require('internal/modules/esm/utils');

const { decorateErrorStack } = require('internal/util');
const {
Expand Down Expand Up @@ -60,6 +59,14 @@ class ModuleJob {

module;

/**
*
* @param {URL['href']} url The resolved url of the module.
* @param {ModuleWrap} moduleWrapper
* @param {*} importAssertions
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* @param {*} importAssertions
* @param {Record<string, string>} importAssertions

Or use whatever JSDoc we use for these elsewhere.

* @param {boolean} isMain Whether this is the main module.
* @param {boolean} inspectBrk Whether to invoke the inspector and break on start.
*/
constructor(
url,
moduleWrapper,
Expand All @@ -74,18 +81,6 @@ class ModuleJob {

debug('ModuleJob::constructor(%o)', { url, importAssertions, isMain, inspectBrk });

// Expose the promise to the ModuleWrap directly for linking below.
// `this.module` is also filled in below.

setCallbackForWrap(this.modulePromise, {
initializeImportMeta: (meta, wrap) => this.importMetaInitialize(meta, { url }),
importModuleDynamically: (specifier, { url }, importAssertions) => {
const moduleLoader = require('internal/process/esm_loader').esmLoader;
debug('ModuleJob::importModuleDynamically(%o)', { specifier, url, moduleLoader });
return moduleLoader.import(specifier, url, importAssertions);
},
});

// Wait for the ModuleWrap instance being linked with all dependencies.
const link = async () => {
this.module = await this.modulePromise;
Expand All @@ -98,11 +93,11 @@ class ModuleJob {
// these `link` callbacks depending on each other.
const dependencyJobs = [];
debug('this.module.link: %o', { [url]: this.module.link.toString() });
const promises = this.module.link((specifier, assertions) => {
const promises = this.module.link(async (specifier, assertions) => {
debug('this.module.link(%o)', { specifier, assertions });
const moduleLoader = require('internal/process/esm_loader').esmLoader;
anonrig marked this conversation as resolved.
Show resolved Hide resolved
debug('this.module.link() moduleLoader: %s', moduleLoader.constructor.name);
const job = moduleLoader.getModuleJob(specifier, url, assertions);
const job = await moduleLoader.getModuleJob(specifier, url, assertions);
debug('this.module.link() job: %o', job);
ArrayPrototypePush(dependencyJobs, job);
return job.modulePromise;
Expand Down Expand Up @@ -152,8 +147,7 @@ class ModuleJob {
// stack trace originates in module_job, not the file itself. A hidden
// symbol with filename could be set in node_errors.cc to facilitate this.
if (!getSourceMapsEnabled() &&
StringPrototypeIncludes(e.message,
' does not provide an export named')) {
StringPrototypeIncludes(e.message, ' does not provide an export named')) {
const splitStack = StringPrototypeSplit(e.stack, '\n');
const parentFileUrl = RegExpPrototypeSymbolReplace(
/:\d+$/,
Expand All @@ -162,11 +156,10 @@ class ModuleJob {
);
const { 1: childSpecifier, 2: name } = RegExpPrototypeExec(
/module '(.*)' does not provide an export named '(.+)'/,
e.message);
const moduleLoader = require('internal/process/esm_loader').esmLoader;
const { url: childFileURL } = await moduleLoader.resolve(
childSpecifier, parentFileUrl,
e.message,
);
const moduleLoader = require('internal/process/esm_loader').esmLoader;
const { url: childFileURL } = await moduleLoader.resolve(childSpecifier, parentFileUrl);
let format;
try {
// This might throw for non-CommonJS modules because we aren't passing
Expand Down
19 changes: 16 additions & 3 deletions lib/internal/modules/esm/translators.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,13 +103,27 @@ function errPath(url) {
return url;
}

let importMetaInitializer;

// Strategy for loading a standard JavaScript module.
translators.set('module', async function moduleStrategy(url, source, isMain) {
assertBufferSource(source, true, 'load');
source = stringify(source);
maybeCacheSourceMap(url, source);
debug(`Translating StandardModule ${url}`);
debug(`Translating ESModule ${url}`);
const module = new ModuleWrap(url, undefined, source, 0, 0);
const { setCallbackForWrap } = require('internal/modules/esm/utils');
setCallbackForWrap(module, {
initializeImportMeta(meta, wrap) {
importMetaInitializer ??= require('internal/modules/esm/initialize_import_meta').initializeImportMeta;
importMetaInitializer(meta, { url });
},
importModuleDynamically(specifier, { url }, importAssertions) {
const moduleLoader = require('internal/process/esm_loader').esmLoader;
debug('Translator("module")::importModuleDynamically(%o)', { specifier, url, moduleLoader });
return moduleLoader.import(specifier, url, importAssertions);
},
});
return module;
});

Expand All @@ -133,8 +147,7 @@ function enrichCJSError(err, content, filename) {

// Strategy for loading a node-style CommonJS module
const isWindows = process.platform === 'win32';
translators.set('commonjs', async function commonjsStrategy(url, source,
isMain) {
translators.set('commonjs', async function commonjsStrategy(url, source, isMain) {
debug(`Translating CJSModule ${url}`);

const filename = fileURLToPath(new URL(url));
Expand Down