Writing plugins
Extending a Guchho build with resolveId, load, transform and bundle hooks.
#A plugin is a plain object with a name and any of the hooks, run
in the host process while the build runs. It is the way to add resolution rules,
virtual modules, source transforms and output rewrites without forking the
engine.
import { build } from 'guchho'
const env = {
name: 'env-define',
setup() {
// …
},
}
await build({ entrypoints: ['app.js'], plugins: [env] })
Pass a single plugin or an array through the plugins option; the
configuration file nests it under a top-level plugins key.
When the config root is an array of configurations, each element may carry its
own plugins. The host runs one list for the whole run, so the plugins from
every element are collected in order into a single list, and a plugin named by
more than one element is attached once. A plugin is not scoped to the element
that named it - it sees every build in the run.
The shape
#name- required, and it appears in every diagnostic the plugin causes.order-'pre'or'post', where the plugin runs relative to the default order. Plugins with the sameorderrun in the order they appear.- Hooks - every hook is optional, and every hook that can decline does so by
returning
null(or leaving the returnundefined), which says "not mine" rather than "stop".
Every hook can be async. The engine runs the plugins one at a time and waits;
a hook that resolves is a hook the engine continues from.
The lifecycle
#buildStart- once per build, before any file is read.resolveId- asked where a specifier points, for every import and entry point.load- asked for a module's contents, before the loader would read them.transform- rewrites a module's source after it was loaded and before it is parsed.buildEnd- after every module is read;erroris set when the build failed.generateBundle/writeBundle- with the finished output, before and after it is written.closeBundle- when the context is torn down. The last hook a plugin sees.
Hooks and context
#- Hooks - each hook in detail: signature, when it runs, what it answers with.
- Context - what
thisis inside a hook, and what a plugin can ask the build to do.
Types
#The exact type declarations live in the
generated plugin types, produced from
index.d.ts. The short version:
| Type | Means |
|---|---|
Plugin |
A plugin: name, order, and the hooks. |
PluginContext |
this inside a hook. |
PluginOrder |
'pre' | 'post'. |
ResolveIdOptions |
Where a resolveId was asked from. |
ResolvedId |
A resolveId answer: id, external, namespace, meta. |
LoadResult |
A load answer: code, loader, resolveDir, meta. |
SourceDescription |
A transform answer: code and an optional map. |
OutputChunk / OutputAsset |
One file in the bundle a bundle hook sees. |
OutputBundle |
The whole bundle, keyed by file name. |
NormalizedOutputOptions |
The output options a bundle hook is handed. |
EmittedFile |
What this.emitFile puts in the output. |
GuchhoLog |
The shaped object this.warn / this.error accept. |
What a plugin cannot do
#The engine is a native service; a plugin cannot hook into its internals, only into the calls listed above. There is no plugin that runs on the compiler's side of the wire, and no hook past what the engine implements is declared - every hook in the type has a runtime implementation behind it.