Build and bundle a plugin
meridian-plugin build bundles your plugin into a dist/ that the host can load
without any npm install — runtime dependencies are inlined into the emitted
JavaScript. This recipe runs the build and shows how to confirm the artifact is
self-contained. For the reasoning behind the bundle boundary, see
Bundling and distribution; for the
command's flags, see the CLI reference.
Prerequisites
- A plugin project that already compiles — scaffolded per
Scaffold a plugin or an equivalent layout, with a
plugin.yamland its behavior/adapter/source modules in place. - Dependencies installed (
npm install), including any runtime packages your behaviors import.
Run the build
From the plugin root, run the build:
npm run build # → meridian-plugin build (the scaffold wires this up)Equivalently, invoke the CLI directly:
meridian-plugin build [dir=.].Read the summary line. On success the CLI reports the plugin, its version, and the number of bundled modules, and exits zero:
✓ @acme/vitals@0.1.0 → dist/ (1 module(s) bundled, runtime deps included).A non-zero exit means esbuild or the declaration emit failed; the error names the module or tsconfig at fault.
What the build produces
meridian-plugin build (libs/plugin-cli/src/commands/build.ts) wipes and
recreates dist/, then:
- Bundles every module referenced by the manifest — each node
behavior, eachadapter, and eacheventSourcemodule:— with esbuild (format: esm,platform: node,target: node20,splitting: true). Your plugin's runtime dependencies are inlined into the output, so the published artifact carries nonode_modulesof its own. Code shared between modules is factored intodist/chunks/. - Leaves two import families external, because the host guarantees them: Node
builtins (
node:*) and the SDK (@meridian/*). These are never inlined. - Emits TypeScript declarations when the project has a
tsconfig.build.jsonortsconfig.json(tsc --emitDeclarationOnly --noCheck). These back a plugin's./typesexport, consumed by any plugin that declares adependsOnon yours. A project without a tsconfig simply emits none. - Copies
plugin.yamlintodist/, rewriting everymodule:path from.tsto.jsso it points at the bundled output. - Copies
i18n/*.yamlintodist/i18n/, where the host reads them next to the manifest.
dist/ is exactly what you ship — there is no separate packaging step.
Cross-plugin type imports
Imports of a dependency's types (@scope/dep/types) are import type and erased
at compile time, so they never enter the runtime bundle. They only need to
resolve during your own type-check and declaration emit. See
Generate types and
Add vocabulary and types.
Verify the artifact is self-contained
Inspect the tree — you should see the bundled JS, the rewritten manifest, and any i18n and declarations:
ls -R distConfirm your runtime dependencies were inlined rather than left as bare imports. The only imports that may remain in the emitted JS are
node:*and@meridian/*:grep -rE "from \"[^.@]" dist --include="*.js" # bare (non-relative) importsEvery hit should be either a
node:builtin or an@meridian/sub-path. A package name from yourdependenciesappearing here means it was not bundled — see the caveat below.
Caveat: native dependencies cannot be bundled
A bundler inlines JavaScript; it cannot inline a native (compiled) npm
dependency — anything shipping a .node binary or a build step. Avoid such
packages in plugins. If one is genuinely required, it cannot travel in dist/
and must instead be provided by the host image, which puts the burden back on
the operator and breaks the drop-in autonomy a bundled plugin is meant to have.
Next steps
- Publish to the registry — ship the built
dist/withmeridian-plugin publish. - Declare and install plugins — the operator side that loads your artifact.
- Set up a plugin registry — where a published plugin lands.
Related
- Bundling and distribution — why
the SDK and
node:*stay external, and how autonomy is achieved. - Autonomy and packaging — the no-platform-rebuild delivery model.
- CLI reference — every
meridian-plugincommand. - Plugin manifest — the
module:fields the build reads. - Build a plugin, end to end — the full path from scaffold to published plugin.