Static CSS extraction for Next.js (15 and 16). Wraps next.config to integrate the Animus extraction pipeline — webpack and Turbopack.
npm install @animus-ui/next-plugin @animus-ui/system// next.config.mjs
import { withAnimus } from '@animus-ui/next-plugin';
const nextConfig = {
// your existing Next.js config
};
export default withAnimus({
system: './src/ds.ts',
})(nextConfig);Turbopack support activates automatically whenever the process runs under
Turbopack (next dev --turbopack, or Next 16 where Turbopack is the
default) — no config change needed. Extraction runs while next.config
resolves, a watcher re-analyzes on source changes in dev, and per-file
transforms run in a stateless loader fed by generated .animus/ artifacts.
tsconfig paths aliases are honored.
Control it explicitly with the turbopack option:
export default withAnimus({
system: './src/ds.ts',
turbopack: { mode: 'auto' }, // 'auto' (default) | 'on' | 'off'
})(nextConfig);Under webpack (next dev / next build on 15, or --webpack on 16) the
plugin behaves exactly as before.
Optional. Restores a persisted color mode before first paint with zero runtime — a generated, dependency-free inline snippet whose CSP hash is computed at build time from the exact bytes generated.
The plugin deliberately injects nothing: CSP nonces need request-time control
the bundler does not have, so the application places the artifact. Generate
it in a server-only module and inline it as the first child of <head>.
App Router:
// appearance-bootstrap.ts — server-only; never import from a client component
import { createAppearanceBootstrap } from '@animus-ui/system/bootstrap';
import { theme } from './src/ds';
export const appearanceBootstrap = createAppearanceBootstrap(theme);// app/layout.tsx
import { appearanceBootstrap } from '../appearance-bootstrap';
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en" suppressHydrationWarning>
<head>
<script
data-animus-bootstrap=""
dangerouslySetInnerHTML={{ __html: appearanceBootstrap.code }}
/>
</head>
<body>{children}</body>
</html>
);
}Pages Router: same artifact, placed as the first child of <Head> in
pages/_document.tsx, with suppressHydrationWarning on <Html>.
Two rules either way:
suppressHydrationWarningon the root element is required, not cosmetic — the snippet legitimately mutatesdata-color-modebetween SSR and hydration.- Serve a CSP that authorizes the script from the artifact itself: either
script-src '<artifact.cspHash>'(single-quoted, derived at build time — never hand-copied; a renamed mode changes the hash) or a per-request nonce you add to the script tag. The full CSP footguns are documented in the@animus-ui/vite-pluginREADME.
- Transforms
@animus-ui/systembuilder chains into static CSS (webpack loader or Turbopack loader rule) - Emits extracted CSS as a separate asset with
@layerordering - Post-processes the emitted sheet with Lightning CSS — autoprefixed for your
targets(browserslist query; defaults to the project config), minified in production (minifyoverrides) - Works with both App Router and Pages Router
- Supports RSC — no runtime style injection means server components work out of the box
MIT