
Description
Issue
My loader analyzes a full module graph during load to determine module shape (the set of exported names). Walking the whole graph is necessary because wildcard exports can add unspecified names. You've got to walk the full graph to determine the names for one module.
export const value = 1
export * from './source.mjs'
To ensure I'm using the full semantics of active CLI options, feature changes across versions, etc plus semantics changes provided by underlying loaders (such as TypeScript transpilation), I use the nextResolve
and nextLoad
routines in the analysis. They're extracted by the resolve
and load
hooks.
async function resolve (specifier, context, next) {
// Retain resolver for analysis
gear.resolve ??= next
...
async function load (locator, context, next) {
// Retain loader for analysis
gear.load ??= next
...
I see in the code that these routines actually mutate internal state for the particular import operation they were extracted from. Analysis for a single load may apply these routines to hundreds of modules with all different URLs and context
properties. Analysis runs concurrently so many operations are in flight together. So far this doesn't seem to be causing problems, but I'm concerned it's an unsupported use and may break in the future.
When attributes come into use, I wonder if they'll start to drift across concurrent operations.
* @param {object} meta Properties that change as the current hook advances
* along the chain.
ObjectAssign(meta.context, context);
if (output?.shortCircuit === true) { meta.shortCircuited = true; }
Solution
My loader would like a supported way to run resolve and load of the underlying loaders, independent of any import operations, and capable of running concurrently. Maybe they could be passed to initialize
.
function initialize (port, resolve, load) {
gear.resolve = resolve
gear.load = load
...