Skip to content

Entrypoint can be treated as CommonJS when loader chains add query params to file URLs #232

@iblancasa

Description

@iblancasa

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.mjs

Example 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions