Skip to content
Closed
Show file tree
Hide file tree
Changes from 2 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
28 changes: 20 additions & 8 deletions lib/internal/modules/esm/loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -151,22 +151,28 @@ class DefaultModuleLoader {
return this.getJobFromResolveResult(resolveResult, parentURL, importAssertions);
}

getJobFromResolveResult(
async getJobFromResolveResult(
resolveResult,
parentURL,
importAssertions = resolveResult.importAssertions,
) {
const { url, format } = resolveResult;
debug('getJobFromResolveResult:', { [url]: { format, moduleMap: this.moduleMap } });

// `job` may be a Promise, which the engine INSANELY _sometimes_ considers undefined and
// sometimes not. This is why we use `has` instead of `get` to check for its existence.
// ! Do NOT try to check against its value; the engine will **gladly** screw you over.
if (!this.moduleMap.has(url, importAssertions.type)) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

i'm confused why a map's "has" function would ever take more than one argument. is moduleMap something that's not a Map?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Good question! I also had to ask what this is.

The extra argument (import assertion type) is per spec required for matching cache. Under the hood, the extra argument is stored as part of the value (or maybe the key?).

I'll add some code doc for it after I get this stable/passing.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think it’s very confusing to have something called “map” whose method names violate the expected interface contract for a Map, but i assume that predates this PR. (iow, i think instead of using has/set/etc it should have brand new method names)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Yes, this PR does not introduce ModuleMap ;)

debug('getJobFromResolveResult: did NOT find existing entry for %s', url)
return this.#createModuleJob(url, parentURL, importAssertions, format);
}

let job = this.moduleMap.get(url, importAssertions.type);
debug('getJobFromResolveResult: found existing entry for %s %o', url, job);

// CommonJS will set functions for lazy job evaluation.
if (typeof job === 'function') {
if (typeof job === 'function') { // CommonJS will set functions for lazy job evaluation.
this.moduleMap.set(url, undefined, job = job());
Comment thread
JakobJingleheimer marked this conversation as resolved.
}

job ??= this.#createModuleJob(url, parentURL, importAssertions, format);

return job;
}

Expand All @@ -189,6 +195,10 @@ debug('getJobFromResolveResult:', { [url]: { format, moduleMap: this.moduleMap }
process.send({ 'watch:import': [url] });
}

debug('#createModuleJob (before load)', { url, parentURL, importAssertions, format })

// ! The module needing creation is not added to ModuleMap before the next `getModuleJob()`,
// ! which is a problem.
const {
format: finalFormat,
responseURL,
Expand All @@ -205,18 +215,20 @@ debug('getJobFromResolveResult:', { [url]: { format, moduleMap: this.moduleMap }
}

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

const ModuleJob = require('internal/modules/esm/module_job');
const job = new ModuleJob(
responseURL,
url, // TODO: should this be resolvedURL?
moduleWrapper,
importAssertions,
isMain,
inspectBrk,
);

debug('#createModuleJob (translated) %o', { url, job });

this.moduleMap.set(url, importAssertions.type, job);

return job;
Expand Down
8 changes: 6 additions & 2 deletions lib/internal/modules/esm/module_job.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,13 @@ class ModuleJob {
const dependencyJobs = [];
debug('this.module.link: %o', { [url]: this.module.link.toString() });
const promises = this.module.link(async (specifier, assertions) => {
debug('this.module.link(%o)', { specifier, assertions });
const moduleLoader = require('internal/process/esm_loader').esmLoader;
Comment thread
anonrig marked this conversation as resolved.
debug('this.module.link() moduleLoader: %s', moduleLoader.constructor.name);
debug('this.module.link(%o)', {
specifier,
parentURL: url,
assertions,
moduleLoader: moduleLoader.constructor.name
});
const job = await moduleLoader.getModuleJob(specifier, url, assertions);
debug('this.module.link() job: %o', job);
ArrayPrototypePush(dependencyJobs, job);
Expand Down