Skip to content

Commit

Permalink
Adds a loader for manifest loading
Browse files Browse the repository at this point in the history
  • Loading branch information
arcanis committed Nov 10, 2021
1 parent 3a9e140 commit bdc8aff
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 0 deletions.
2 changes: 2 additions & 0 deletions doc/design/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ There are currently [three loader hooks](https://github.com/nodejs/node/tree/mas

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

1. `loadManifest`: Takes the resolved URL and returns the `package.json` from the location (or `null` if it doesn't exist).

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):
* `commonjs`
* `module`
Expand Down
52 changes: 52 additions & 0 deletions doc/design/proposal-chaining-iterative.md
Original file line number Diff line number Diff line change
Expand Up @@ -282,3 +282,55 @@ const babelOutputToFormat = new Map([
]);
```
</details>
## Chaining `loadManifest` hooks
Say you had a chain of three loaders:
* `zip` adds a virtual filesystem layer for in-zip access
* `tgz` does the same but for tgz archives
* `warc` does the same for warc archives.
Following the pattern of `--require`:
```console
node \
--loader zip \
--loader tgz \
--loader warc
```
These would be called in the following sequence:
(`zip` OR `defaultLoadManifest`) → `tgz``warc`
1. `defaultLoadManifest` / `zip` needs to be first to know whether the manifest exists on the actual filesystem, which is fed to the subsequent loader
1. `tgz` receives the raw source from the previous loader and, if necessary, checks for the manifest existence via its own rules
1. `warc` does the same thing
LoadManifest hooks would have the following signature:
```ts
export async function loadManifest(
manifestUrl: string, // A URL that may or may not point to an existing
// location
interimResult: { // result from the previous hook
manifest: string | ArrayBuffer | TypedArray | null, // The content of the
// manifest, or `null` if it doesn't exist.
},
context: {
conditions = string[], // Export conditions of the relevant package.json
parentUrl = null, // The module importing this one, or null if
// this is the Node entry point
},
defaultLoadManifest: function, // Node's default load hook
): {
signals?: { // Signals from this hook to the ESMLoader
contextOverride?: object, // A new `context` argument for the next hook
interimIgnored?: true, // interimResult was intentionally ignored
shortCircuit?: true, // `resolve` chain should be terminated
},
manifest: string | ArrayBuffer | TypedArray | null, // The content of the
// manifest, or `null` if it doesn't exist.
} {
```
41 changes: 41 additions & 0 deletions doc/design/proposal-chaining-middleware.md
Original file line number Diff line number Diff line change
Expand Up @@ -263,3 +263,44 @@ export async function load(
}
```
</details>
## Chaining `loadManifest` hooks
Say you had a chain of three loaders:
* `zip` adds a virtual filesystem layer for in-zip access
* `tgz` does the same but for tgz archives
* `warc` does the same for warc archives.
Following the pattern of `--require`:
```console
node \
--loader zip \
--loader tgz \
--loader warc
```
These would be called in the following sequence: `zip` calls `tgz`, which calls `warc`. Or in JavaScript terms, `zip(tgz(warc(input)))`:
Load hooks would have the following signature:
```ts
export async function loadManifest(
manifestUrl: string, // A URL that may or may not point to an existing
// location
context: {
conditions = string[], // Export conditions of the relevant `package.json`
parentUrl = null, // The module importing this one, or null if
// this is the Node entry point
},
next: function, // The subsequent `loadManifest` hook in the chain,
// or Node’s default `loadManifest` hook after the
// last user-supplied `loadManifest` hook
): {
manifest: string | ArrayBuffer | TypedArray | null, // The content of the
// manifest, or `null` if it doesn't exist.
shortCircuit?: true, // A signal that this hook intends to terminate
// the chain of `load` hooks
} {
```

0 comments on commit bdc8aff

Please sign in to comment.