Skip to content

Module hooks' context.importAttributes is undefined for require(), but documented as an <Object> #67209

Open

Description

@alvaro-cuesta

Affected URL(s)

Description of the problem

Both hooks document context.importAttributes as an <Object>, but for a module that require() loads it's undefined. That looks deliberate: the CommonJS loader passes /* importAttributes */ undefined to the hooks (resolve, load, load), and customization_hooks.js types it ImportAttributes|undefined.

So a hook written from the docs, e.g. context.importAttributes.type === "json", throws as soon as anything is require()d, which in practice means as soon as a CommonJS dependency loads. @types/node follows the docs too (importAttributes: ImportAttributes), so TypeScript doesn't catch it either.

On v26.13.0, logging it from registerHooks() for require() and import() of the same kinds of files:

load    main.cjs {}
resolve ./a.cjs undefined
load    a.cjs undefined
resolve ./b.mjs undefined
load    b.mjs undefined
resolve ./c.json undefined
load    c.json undefined
resolve ./b.mjs?x {}
load    b.mjs?x {}
resolve ./c.json?x {"type":"json"}
load    c.json?x {"type":"json"}
Repro

hooks.mjs:

import { registerHooks } from "node:module";

registerHooks({
  resolve(specifier, context, nextResolve) {
    if (specifier.startsWith("./")) {
      console.log("resolve", specifier, JSON.stringify(context.importAttributes));
    }
    return nextResolve(specifier, context);
  },
  load(url, context, nextLoad) {
    if (url.startsWith("file:")) {
      console.log("load   ", url.split("/").pop(), JSON.stringify(context.importAttributes));
    }
    return nextLoad(url, context);
  },
});

main.cjs:

require("./a.cjs");
require("./b.mjs");
require("./c.json");
import("./b.mjs?x").then(() => import("./c.json?x", { with: { type: "json" } }));

With a.cjs (module.exports = 1;), b.mjs (export default 2;) and c.json ({"c":3}) next to it: node --import ./hooks.mjs main.cjs.

Either documenting it as <Object> | <undefined> (undefined for require()), or passing {} there, as import() without attributes already gets, would fix it. If it's meant to stay undefined, documenting that is enough, and @types/node can follow.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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