From 20e0ba3b94c4890fc32a95b754afe97f18e4fd18 Mon Sep 17 00:00:00 2001 From: Jacob Smith <3012099+JakobJingleheimer@users.noreply.github.com> Date: Sat, 2 Mar 2024 15:33:25 +0100 Subject: [PATCH] doc,module: clarify hook chain execution sequence PR-URL: https://github.com/nodejs/node/pull/51884 Reviewed-By: Luigi Pinca Reviewed-By: Geoffrey Booth --- doc/api/module.md | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/doc/api/module.md b/doc/api/module.md index 9ddd0a64642e9d..a9ee987f667ef6 100644 --- a/doc/api/module.md +++ b/doc/api/module.md @@ -268,8 +268,8 @@ It's possible to call `register` more than once: // entrypoint.mjs import { register } from 'node:module'; -register('./first.mjs', import.meta.url); -register('./second.mjs', import.meta.url); +register('./foo.mjs', import.meta.url); +register('./bar.mjs', import.meta.url); await import('./my-app.mjs'); ``` @@ -279,20 +279,23 @@ const { register } = require('node:module'); const { pathToFileURL } = require('node:url'); const parentURL = pathToFileURL(__filename); -register('./first.mjs', parentURL); -register('./second.mjs', parentURL); +register('./foo.mjs', parentURL); +register('./bar.mjs', parentURL); import('./my-app.mjs'); ``` -In this example, the registered hooks will form chains. If both `first.mjs` and -`second.mjs` define a `resolve` hook, both will be called, in the order they -were registered. The same applies to all the other hooks. +In this example, the registered hooks will form chains. These chains run +last-in, first out (LIFO). If both `foo.mjs` and `bar.mjs` define a `resolve` +hook, they will be called like so (note the right-to-left): +node's default ← `./foo.mjs` ← `./bar.mjs` +(starting with `./bar.mjs`, then `./foo.mjs`, then the Node.js default). +The same applies to all the other hooks. The registered hooks also affect `register` itself. In this example, -`second.mjs` will be resolved and loaded per the hooks registered by -`first.mjs`. This allows for things like writing hooks in non-JavaScript -languages, so long as an earlier registered loader is one that transpiles into -JavaScript. +`bar.mjs` will be resolved and loaded via the hooks registered by `foo.mjs` +(because `foo`'s hooks will have already been added to the chain). This allows +for things like writing hooks in non-JavaScript languages, so long as +earlier registered hooks transpile into JavaScript. The `register` method cannot be called from within the module that defines the hooks. @@ -367,11 +370,11 @@ export async function load(url, context, nextLoad) { } ``` -Hooks are part of a chain, even if that chain consists of only one custom -(user-provided) hook and the default hook, which is always present. Hook +Hooks are part of a [chain][], even if that chain consists of only one +custom (user-provided) hook and the default hook, which is always present. Hook functions nest: each one must always return a plain object, and chaining happens as a result of each function calling `next()`, which is a reference to -the subsequent loader's hook. +the subsequent loader's hook (in LIFO order). A hook that returns a value lacking a required property triggers an exception. A hook that returns without calling `next()` _and_ without returning @@ -1049,6 +1052,7 @@ returned object contains the following keys: [`register`]: #moduleregisterspecifier-parenturl-options [`string`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String [`util.TextDecoder`]: util.md#class-utiltextdecoder +[chain]: #chaining [hooks]: #customization-hooks [load hook]: #loadurl-context-nextload [module wrapper]: modules.md#the-module-wrapper