Skip to content

esm: add chaining to loaders

Notable changes

  • ESMLoader now provides more detailed error messages for hooks, including the specific file and hook from which the error was caused (ex the hook broke the chain; but not SyntaxError within the hook—which was already working). In order to facilitate this:
    • ESMLoader's internal collections of hooks have changed from hook fn[]Array<{ url: specifier, fn: hook }>
    • ESMLoader::import()'s return has changed from ModuleNamespace[] | ModuleNamespaceArray<{ url: specifier, fn: hook }> | ModuleNamespace

TODOs:

  • hook up next()s
  • custom loaders FIFO → LIFO
  • detect & throw on unsignalled short-circuit
  • update existing hook output error messages to include newly available specifier
  • update code docs
  • update Error docs
  • update ESM docs
  • verify/fix node-land breakages caused the change to ESMLoader::import() (I think this will not be a breaking change to user-land as the functionality seen in user-land continues to be where ESMLoader::import() returns a single ModuleNamespace)
  • update current tests
  • add new tests for chaining

Trying it out

CLI
./node \
    --loader=/PATH/TO/loaderA.mjs \
    --loader=/PATH/TO/loaderB.mjs \
    --input-type=module \
    -e "import fs from 'node:fs'; console.log(2)"
loaderA.mjs
export const resolve = async function resolveA(
	specifier,
	context,
	next,
) {
	console.log('resolveA running');
	return {
		shortCircuit: true,
		url: 'file:///foo/bar.js',
	};
}
export const load = async function loadA(
	resolvedUrl,
	context,
	next,
) {
	console.log('loadA running');
	return {
		format: 'module',
		shortCircuit: true,
		source: 'export default 42',
	}
}
loaderB.mjs
export const resolve = async function resolveB(
	specifier,
	context,
	next,
) {
	console.log('resolveB running');
	return next(specifier);
}
export const load = async function loadB(
	resolvedUrl,
	context,
	next,
) {
	console.log('loadB running');
	return next(resolvedUrl);
}

42 should be printed to stdout when the hooks are properly chained; when disabled, the node:fs module should be printed to stdout.

Merge request reports

Loading