new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

Deno · Reference · all subjects

runtime api

17 notes, read out of this brain and free to use. Each one was extracted from a source and is re-checked against its exam.

registerHooks() API for module interception

Deno supports the Node.js module.registerHooks() API, which lets you intercept and customize how modules are resolved and loaded. This enables virtual modules, custom transpilation, module aliasing, and similar use cases without modifying the importing code. The hooks are synchronous and run in the same thread as your application. They work for both ES modules (import) and CommonJS (require()).

registerHooks() does not support async module.register() API

Deno does not implement the asynchronous module.register() API. Use registerHooks() for both CommonJS and ESM customization.

resolve hook parameters and context

The resolve hook signature is: resolve(specifier, context, nextResolve). Parameters: specifier (string) is the module specifier being resolved; context (object) is the resolution context; nextResolve (function) delegates to the next hook or the default resolver. Context object properties: conditions (string[]) are import conditions (e.g., ["node", "import"] for ESM); parentURL (string) is the URL of the importing module; importAttributes (object) are import attributes from the import statement.

resolve hook return value

The resolve hook must return an object with: url (string) - the resolved URL for the module; shortCircuit (boolean) - if true, skip remaining hooks in the chain. Either call nextResolve() to delegate, or return a result with shortCircuit: true. You must do one or the other.

load hook parameters and context

The load hook signature is: load(url, context, nextLoad). Parameters: url (string) is the resolved module URL; context (object) is the load context; nextLoad (function) delegates to the next hook or the default loader. Context object properties: format (string) is module format hint (e.g., "module", "commonjs"); conditions (string[]) are import conditions; importAttributes (object) are import attributes.

load hook return value

The load hook must return an object with: source (string | Buffer | null) - the module source code; format (string) - module format which must be "module", "commonjs", or "json"; shortCircuit (boolean) - if true, skip remaining hooks in the chain.

registerHooks() return value and deregister method

registerHooks() returns an object with a deregister() method to remove the hooks. Call hooks.deregister() to remove the registered hooks.

Hook chaining and LIFO execution order

You can register multiple hooks; they form a chain. Hooks run in LIFO (last registered, first called) order, and each hook can call nextResolve() / nextLoad() to pass control to the previous hook in the chain.

Basic registerHooks example with resolve and load hooks

Example showing virtual module creation: import { registerHooks } from "node:module"; const hooks = registerHooks({ resolve(specifier, context, nextResolve) { if (specifier === "virtual:greet") { return { url: "file:///virtual_greet.js", shortCircuit: true }; } return nextResolve(specifier, context); }, load(url, context, nextLoad) { if (url === "file:///virtual_greet.js") { return { source: 'export const msg = "hello from hooks";', format: "module", shortCircuit: true, }; } return nextLoad(url, context); }, }); const { msg } = await import("virtual:greet"); console.log(msg); // "hello from hooks" hooks.deregister();

Custom transpilation use case for loader hooks

Example showing custom file format transpilation: import { registerHooks } from "node:module"; registerHooks({ load(url, context, nextLoad) { if (url.endsWith(".coffee")) { const result = nextLoad(url, context); const compiled = compileCoffeeScript(result.source); return { source: compiled, format: "module", shortCircuit: true }; } return nextLoad(url, context); }, });

Module aliasing use case for loader hooks

Example showing module import redirection: import { registerHooks } from "node:module"; registerHooks({ resolve(specifier, context, nextResolve) { // Redirect lodash to lodash-es if (specifier === "lodash") { return nextResolve("lodash-es", context); } return nextResolve(specifier, context); }, });

Virtual modules use case for loader hooks

Example showing modules that exist only in memory: import { registerHooks } from "node:module"; const virtualModules = new Map([ ["virtual:config", 'export default { debug: true, version: "1.0.0" };'], ["virtual:env", `export const NODE_ENV = "${process.env.NODE_ENV}";`], ]); registerHooks({ resolve(specifier, context, nextResolve) { if (virtualModules.has(specifier)) { return { url: `file:///virtual/${specifier}`, shortCircuit: true }; } return nextResolve(specifier, context); }, load(url, context, nextLoad) { for (const [name, source] of virtualModules) { if (url === `file:///virtual/${name}`) { return { source, format: "module", shortCircuit: true }; } } return nextLoad(url, context); }, });

Mocking for tests use case for loader hooks

Example showing module replacement during testing: import { registerHooks } from "node:module"; const hooks = registerHooks({ resolve(specifier, context, nextResolve) { if (specifier === "./database.js") { return { url: "file:///mock_database.js", shortCircuit: true }; } return nextResolve(specifier, context); }, load(url, context, nextLoad) { if (url === "file:///mock_database.js") { return { source: 'export const query = () => [{ id: 1, name: "mock" }];', format: "module", shortCircuit: true, }; } return nextLoad(url, context); }, }); // Run tests... hooks.deregister(); // Clean up after tests

External dependencies in hook-generated source are not auto-resolved

jsr:, npm:, and https: specifiers are not resolved automatically when they appear only in source produced by a hook. This applies to any load hook that returns source Deno did not read from disk itself. Deno discovers and installs external dependencies by statically analyzing your module graph before execution. Source returned from a load hook is generated at load time after that analysis has completed, so any bare jsr:, npm:, or https: import that only appears in the emitted source is invisible to dependency resolution.

Declaring external dependencies for hook-generated code

To use an external dependency from hook-generated code, declare it up front so it is part of the resolved package set. For example, add it to the imports map in your deno.json: {"imports": {"lodash-es": "npm:lodash-es@latest"}} and import it by its mapped name from the generated source. This ensures dependency resolution is deterministic and lockfile-driven.

CommonJS support for registerHooks

Hooks also intercept require() in CommonJS. Example: const { registerHooks } = require("module"); const hooks = registerHooks({ resolve(specifier, context, nextResolve) { if (specifier === "virtual-module") { return { url: "file:///virtual.js", shortCircuit: true }; } return nextResolve(specifier, context); }, load(url, context, nextLoad) { if (url === "file:///virtual.js") { return { source: "module.exports = { value: 42 }", format: "commonjs", shortCircuit: true, }; } return nextLoad(url, context); }, }); const mod = require("virtual-module"); console.log(mod.value); // 42 hooks.deregister();

Hook chaining example with LIFO execution

Example showing multiple hooks running in LIFO order: import { registerHooks } from "node:module"; // Hook 1: registered first, runs second const hook1 = registerHooks({ load(url, context, nextLoad) { const result = nextLoad(url, context); if (url.includes("target.js")) { return { source: 'export default "from hook1"', format: "module", shortCircuit: true, }; } return result; }, }); // Hook 2: registered second, runs first const hook2 = registerHooks({ load(url, context, nextLoad) { const result = nextLoad(url, context); // Calls hook1 if (url.includes("target.js")) { return { source: 'export default "from hook2"', format: "module", shortCircuit: true, }; } return result; }, }); // Result comes from hook2 since it runs first (LIFO)

Give your agent this brain