-
Notifications
You must be signed in to change notification settings - Fork 52
Description
When the entrypoint URL includes a query string, the loader can classify wrongly the entry-point as non-file because the extension regex only matches if the extension is at the end of the URL.
For example, an entry-point like file:///path/handler.mjs?iitm=true does not match the extension regex, so the entrypoint is treated as CommonJS and can break ESM startup.
In environments that use ESM loader chaining (for example the OpenTelemetry Node instrumentation hook at @opentelemetry/instrumentation/hook.mjs, which re-exports the import-in-the-middle hook and is enabled via --experimental-loader), the entry-point URL can be returned already tagged by a loader or runtime before import-in-the-middle sees it.
This code can help to explain the problem:
// save as resolve-only-loader.mjs
import { createHook } from 'import-in-the-middle/create-hook.mjs';
const { resolve } = createHook(import.meta);
export async function resolveHook(specifier, context, nextResolve) {
if (!context.parentURL) {
const base = await nextResolve(specifier, context);
const url = new URL(base.url);
url.searchParams.set('iitm', 'true');
const tagged = { ...base, url: url.href };
const result = await resolve(url.href, context, async () => tagged);
console.log('iitm resolve result', result);
return result;
}
return resolve(specifier, context, nextResolve);
}
export { resolveHook as resolve };node --experimental-loader ./resolve-only-loader.mjs ./entry.mjsExample output shows the entrypoint URL ending in .mjs?iitm=true is resolved with format commonjs.
This affects any extension that the entrypoint regex checks for because the query string prevents a match.