A simple, folder-driven static-site engine.
bun ssg fs
at dev 85 lines 3.2 kB view raw view rendered
1# Plugins 2 3How to write and register a Webette plugin with the current API. 4 5## Quick start 6 71) Create an ESM file under the site root, e.g. `_plugins/my-plugin.js`. 82) Export an object with any hooks you need. 93) Reference it in `webette.config.ts`: 10```ts 11export default { 12 // ... 13 plugins: ["_plugins/my-plugin.js"], 14}; 15``` 16 17## Hooks you can implement 18 19- `onInit(ctx)` — after env/site load, before scan. 20- `onScan(site, ctx)` — after scan/routes, before content resolution. Return a new site or mutate in place. 21- `onResolved(site, ctx)` — after content resolution, before timestamps/export. Return a new site or mutate in place. 22- `transformBlock(block, ctx)` — per-block mutation (depth-first). Return a new block or mutate. `ctx` includes `entry` and `collection`. 23- `transformEntry(entry, ctx)` — per-entry mutation after blocks. Return a new entry or mutate. `ctx` includes `collection`. 24- `extendTemplates(handlebars, ctx)` — register helpers/partials/layouts before templates are compiled. 25 26Hooks run in that order: init -> scan -> resolved -> transformBlock -> transformEntry -> extendTemplates. 27 28## Context (`ctx`) 29 30Always available: 31- `rootDir` — absolute site root. 32- `env` — loaded `webette.tool.ts` config. 33- `logger` — child logger for your plugin. 34- `readContent` — whether the build is allowed to read block contents. 35- `exportDir``_public/_model` (resolved). 36- `pluginId` — the id of this plugin (filename-based if not provided). 37- `addExpectedOutput(relativePath)` — whitelist one file (relative to output dir) so prune keeps it. 38- `addExpectedDir(relativeDir)` — whitelist a whole directory/prefix under the output; all files inside are kept by prune. 39 40Extra in some hooks: 41- `collection` (transformEntry/transformBlock) 42- `entry` (transformBlock) 43 44## Prune and assets 45 46When `overwrite=replace-files`, Webette deletes any file not expected. If your plugin writes assets or pages: 47- Use `addExpectedOutput("assets/images/plugins/foo/thumb.webp")` for single files. 48- Use `addExpectedDir("assets/images/plugins/foo")` if you generate many files under one folder. 49Paths are always relative to the output folder (e.g. `_public` by default). 50 51## Template extensions 52 53`extendTemplates(handlebars, ctx)` lets you add: 54- helpers: `handlebars.registerHelper("name", fn)` 55- partials: `handlebars.registerPartial("name", templateString)` 56- layouts: write a file and register it as a partial; reference by name from templates. 57 58Site templates override tool templates. In serve mode, the site templates are watched if present; otherwise the tool templates are watched. 59 60## Simple example 61 62```js 63export default { 64 pluginId: "example", 65 66 onResolved(site, ctx) { 67 ctx.logger.info("plugin.example", { entries: site.collections?.length ?? 0 }); 68 }, 69 70 transformBlock(block, ctx) { 71 if (block.type !== "image") return; 72 // Keep all generated variants under this folder 73 ctx.addExpectedDir(`assets/images/plugins/${ctx.entry.slug}`); 74 return { 75 ...block, 76 content: { 77 ...block.content, 78 note: "handled by example plugin", 79 }, 80 }; 81 }, 82}; 83``` 84 85Plugins run locally with full access; there is no sandbox. Keep paths relative to the output dir when using prune APIs.