Skip to content

Commit bdc8aff

Browse files
committed
Adds a loader for manifest loading
1 parent 3a9e140 commit bdc8aff

File tree

3 files changed

+95
-0
lines changed

3 files changed

+95
-0
lines changed

doc/design/overview.md

+2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ There are currently [three loader hooks](https://github.com/nodejs/node/tree/mas
44

55
1. `resolve`: Takes a specifier (the string after `from` in an `import` statement) and converts it into an URL to be loaded.
66

7+
1. `loadManifest`: Takes the resolved URL and returns the `package.json` from the location (or `null` if it doesn't exist).
8+
79
1. `load`: Takes the resolved URL and returns runnable code (JavaScript, Wasm, etc.) as well as the name of one of Node’s ESM loader’s [“translators”](https://github.com/nodejs/node/blob/master/lib/internal/modules/esm/translators.js):
810
* `commonjs`
911
* `module`

doc/design/proposal-chaining-iterative.md

+52
Original file line numberDiff line numberDiff line change
@@ -282,3 +282,55 @@ const babelOutputToFormat = new Map([
282282
]);
283283
```
284284
</details>
285+
286+
## Chaining `loadManifest` hooks
287+
288+
Say you had a chain of three loaders:
289+
290+
* `zip` adds a virtual filesystem layer for in-zip access
291+
* `tgz` does the same but for tgz archives
292+
* `warc` does the same for warc archives.
293+
294+
Following the pattern of `--require`:
295+
296+
```console
297+
node \
298+
--loader zip \
299+
--loader tgz \
300+
--loader warc
301+
```
302+
303+
These would be called in the following sequence:
304+
305+
(`zip` OR `defaultLoadManifest`) → `tgz``warc`
306+
307+
1. `defaultLoadManifest` / `zip` needs to be first to know whether the manifest exists on the actual filesystem, which is fed to the subsequent loader
308+
1. `tgz` receives the raw source from the previous loader and, if necessary, checks for the manifest existence via its own rules
309+
1. `warc` does the same thing
310+
311+
LoadManifest hooks would have the following signature:
312+
313+
```ts
314+
export async function loadManifest(
315+
manifestUrl: string, // A URL that may or may not point to an existing
316+
// location
317+
interimResult: { // result from the previous hook
318+
manifest: string | ArrayBuffer | TypedArray | null, // The content of the
319+
// manifest, or `null` if it doesn't exist.
320+
},
321+
context: {
322+
conditions = string[], // Export conditions of the relevant package.json
323+
parentUrl = null, // The module importing this one, or null if
324+
// this is the Node entry point
325+
},
326+
defaultLoadManifest: function, // Node's default load hook
327+
): {
328+
signals?: { // Signals from this hook to the ESMLoader
329+
contextOverride?: object, // A new `context` argument for the next hook
330+
interimIgnored?: true, // interimResult was intentionally ignored
331+
shortCircuit?: true, // `resolve` chain should be terminated
332+
},
333+
manifest: string | ArrayBuffer | TypedArray | null, // The content of the
334+
// manifest, or `null` if it doesn't exist.
335+
} {
336+
```

doc/design/proposal-chaining-middleware.md

+41
Original file line numberDiff line numberDiff line change
@@ -263,3 +263,44 @@ export async function load(
263263
}
264264
```
265265
</details>
266+
267+
## Chaining `loadManifest` hooks
268+
269+
Say you had a chain of three loaders:
270+
271+
* `zip` adds a virtual filesystem layer for in-zip access
272+
* `tgz` does the same but for tgz archives
273+
* `warc` does the same for warc archives.
274+
275+
Following the pattern of `--require`:
276+
277+
```console
278+
node \
279+
--loader zip \
280+
--loader tgz \
281+
--loader warc
282+
```
283+
284+
These would be called in the following sequence: `zip` calls `tgz`, which calls `warc`. Or in JavaScript terms, `zip(tgz(warc(input)))`:
285+
286+
Load hooks would have the following signature:
287+
288+
```ts
289+
export async function loadManifest(
290+
manifestUrl: string, // A URL that may or may not point to an existing
291+
// location
292+
context: {
293+
conditions = string[], // Export conditions of the relevant `package.json`
294+
parentUrl = null, // The module importing this one, or null if
295+
// this is the Node entry point
296+
},
297+
next: function, // The subsequent `loadManifest` hook in the chain,
298+
// or Node’s default `loadManifest` hook after the
299+
// last user-supplied `loadManifest` hook
300+
): {
301+
manifest: string | ArrayBuffer | TypedArray | null, // The content of the
302+
// manifest, or `null` if it doesn't exist.
303+
shortCircuit?: true, // A signal that this hook intends to terminate
304+
// the chain of `load` hooks
305+
} {
306+
```

0 commit comments

Comments
 (0)