Plugins
2 minutes read
A site adds behavior from mizzen.config.ts at its root. The file default-exports its plugins and nothing else:
import type { Plugin } from "@velella/mizzen/contracts";
export default {
plugins: [
/* Plugin objects, in the order they run. */
],
};
A site without the file is an ordinary site: no plugins, no diagnostics. A file Node cannot import, or a default export without a plugins list, is one error naming the file. An entry that is not a plugin is dropped with an error and the sound entries still run.
A plugin is a name for diagnostics and any of three hooks. Each hook receives a value and returns the value the next plugin receives; none mutates its input. A hook may be async, and it is awaited before the next plugin runs.
| Hook | Runs | Receives | Returns |
|---|---|---|---|
content |
Once per page, after its Markdown is parsed and before the site model is assembled. | Page |
Page |
model |
Once, after the site model is assembled and before anything is rendered. | Site |
Site |
outputs |
Once, with the files the outputs produced and the site they came from, before the files are written. | readonly OutputFile[], Site |
readonly OutputFile[] |
A hook that throws, or returns something the stage cannot use, is an error naming the plugin. The value the stage carried before that plugin is kept and the plugins after it still run, so one bad plugin costs its own work and nothing more. The diagnostic id is plugin.hook-failed.
import type { Plugin } from "@velella/mizzen/contracts";
const banner: Plugin = {
name: "banner",
content(page) {
return { ...page, frontMatter: { ...page.frontMatter, banner: true } };
},
};
export default { plugins: [banner] };
The loader and the hook runners are loadCodeConfig(), runContentHooks(), runModelHooks(), and runOutputsHooks() in src/plugins/hooks.ts. Each runner returns { value, diagnostics } and never fails the stage. build() loads mizzen.config.ts and runs every hook in the order above, once per stage, before anything is written. A site with a code file always builds cold, since what its imports read cannot be part of the cache key, and the file itself is never copied into the output.