@animus-ui/unplugin
Animus transform host for non-plugin bundlers — rollup, esbuild, rspack,
and webpack entry points over the one extraction session. Transforms
@animus-ui/system builder chains into static CSS at build time, delivers
the stylesheet as a real emitted asset (animus.css), and supplies the
__ANIMUS_DEV__ define.
Vite users: use @animus-ui/vite-plugin. Next.js users:
use @animus-ui/next-plugin. The root export's reachable
.vite adapter is unsupported — the supported surface is exactly the
four subpath entries below.
Install
npm install --save-dev @animus-ui/unplugin
npm install @animus-ui/system
Requires Node >=22.12.0. Native engine binaries ship for darwin-arm64,
linux-x64-gnu, and linux-arm64-gnu.
Setup (rollup)
// rollup.config.mjs — ESM configs use the NAMED export.
import { animusRollup as animus } from '@animus-ui/unplugin/rollup';
import esbuild from 'rollup-plugin-esbuild';
export default {
input: 'src/entry.tsx',
plugins: [
// The host FIRST: its transform must see raw TSX (rollup has no
// enforce ordering — config order is the law).
animus({ system: './src/ds.ts', strict: true }),
esbuild({ jsx: 'automatic', target: 'es2022' }),
],
output: { dir: 'dist', format: 'esm' },
};
The other bundlers follow the same shape from their own subpaths:
animusEsbuild from @animus-ui/unplugin/esbuild, animusRspack from
@animus-ui/unplugin/rspack, animusWebpack from
@animus-ui/unplugin/webpack. In CJS config files use the default export:
// CJS config files:
const animus = require('@animus-ui/unplugin/rollup').default;
A Node-ESM default import of the CJS build binds the exports object, not the plugin function — in ESM configs, always use the named export.
Plugin ordering
The extraction engine parses raw TSX — this host's transform must run
before any TS/JSX transpilation. enforce: 'pre' orders webpack and rspack
loader chains automatically; rollup consumers must list this plugin
before their transpiler in the config. Mis-ordered builds emit a
source-drift warning (transform-time source … differs from analyze-time source) followed by a bundler parse error on TSX syntax — move the Animus
plugin first to fix it.
What it does
- Runs the one
ExtractionSessionatbuildStartinside your bundler's process; per-file transforms come from retained engine state. Analysis failure is build failure — never a silent passthrough. - Resolves the stylesheet id (
.animus/styles.css), the system-props id, and one redirect per admitted design-system kit specifier to the exact entry extraction analyzed. tsconfigpathsare the alias source. - Emits the extracted stylesheet as a real
animus.cssasset (for esbuild: written intooutdir, or besideoutfile). - With
stylesheets: 'split', also emits the stylesheet as consecutive slices besideanimus.css,animus.<slice>.<hash>.css(foundation, components, utilities), andanimus-stylesheets.json, their names in link order. Their bytes in order areanimus.css's; a slice an edit leaves alone keeps its name. A later build into the same directory removes the slices it no longer publishes, and the index when it publishes none. - Supplies the
__ANIMUS_DEV__dev-signal define through each bundler's own mechanism. - When a font face declares
preload: true, emitsanimus-font-preloads.jsonbesideanimus.css: the preloads, as{ href, type, fetchpriority }, with hrefs relative to the stylesheet.renderFontPreloads(preloads, { base, exclude })returns the<link>tags for your HTML, wherebaseis the URLanimus.css's directory is served at, andexcludelists hrefs the document already preloads. ThefontPreloadsoption (family names, or{ family, weight?, style?, unicodeRange?, fetchpriority? }) selects the faces that preload in place of theirpreloadflags; an entry'sfetchpriorityreaches their tags.
Options
Options are the shared driver core (system, exclude, strict, mode,
targets, minify, …); unknown keys fail loud. mode
('development' | 'production') selects emission only — the minify
default, the dev-signal define, engine dev diagnostics — never process
lifecycle. When absent, the bundler's own command oracle applies (webpack/
rspack compiler.options.mode, rollup watch mode), else production
(esbuild exposes no signal). exclude patterns are glob-aware; a list
REPLACES the dist, .test. and .spec. defaults, while node_modules,
.next and .animus always apply. Wherever the bundler writes is
always excluded too: its output directories (every Vite environment's,
each output's dir, webpack's output.path up to its first […]
placeholder) and its output files by exact name (outfile,
output.file). webpack, rspack, esbuild and Vite name them before
analysis. Rollup and Rolldown name them only after analysis, so a watch
excludes them from its second build on, and a build that has already
analysed one reports it (an output file as earlier output; a file inside
an output directory as earlier output or a source beside the output),
naming what to add to exclude; under strict that build fails.
The full consumer contract — module-id families, the define contract, artifact set, platform matrix — lives in the standalone extraction contract.
License
MIT