/** * `@nifrajs/web/plugins/css-modules` - a dependency-free CSS Modules (`*.module.css`) Bun plugin, in its * OWN module so the SSR preload registers it BEFORE any `.module.css` file loads. Mirrors the * `@nifrajs/web-vue/plugin` seam exactly: pass `"dom"` for the client bundle * (`buildClient({ plugins: [...] })`) and preload `"ssr"` for the server (`bun --preload`). * * Each `import styles from "./x.module.css"` becomes a JS module whose **default export** is the * `{ originalClassName: scopedClassName }` map; the rewritten (scoped) CSS is emitted into the client * stylesheet via the `?nifra-css-module` virtual-module idiom (the same trick the Vue plugin uses for * `?vue-css`). The `"ssr"` form emits **no** CSS - the stylesheet ships from the client build - but * produces the **identical** class map, so SSR markup's `class={styles.foo}` matches the bundled * selectors (scoped names are a pure function of file path + class name, so both builds agree). * * Scoping is deterministic (a stable 8-hex hash of the package-relative `filePath + className`, no * `Date.now`/`Math.random`/cwd), so builds are reproducible across machines and working directories. * Supported (the 95% case): class selectors (`.a`, `.a .b`, `.a.b`), combinators, * pseudo-classes/`:not(...)`, native nesting, at-rules (`@media`/`@supports`/`@container`/`@layer`), * `:global(...)`/`:local(...)` (function form), and **`@keyframes` names + their `animation`/ * `animation-name` references** (scoped together, so two modules' same-named keyframes don't clash). * Not handled: the bare `:global`/`:local` *switch* form and `composes:` - out of scope by design. */ import type { BunPlugin } from "bun"; /** * The scoped name for a class. Keyed by `filePath` + `className` (NUL-separated so `"a"+"bc"` can't * collide with `"ab"+"c"`), so the same class name in two different files gets two different scoped * names - cross-file collision resistance - while staying stable across builds. * * Exported because it is the definition of the name, and the OTHER pipeline has to be able to produce * it: Vite ships its own CSS-Modules naming, so without handing Vite this function a class is called * one thing under `nifra dev --vite` and another after `nifra build`. `filePath` must be the * package-relative form from `reproduciblePath`, never an absolute path, or the name stops being * reproducible across machines. */ export declare function scopedName(filePath: string, className: string): string; /** The transform result: the `{ original: scoped }` export map + the rewritten (scoped) stylesheet. */ export interface CssModuleResult { readonly exports: Readonly>; readonly css: string; } /** * Pure core (no I/O): scope a CSS-module source. Same `(source, filePath)` in → byte-identical out, so * the `"dom"` and `"ssr"` plugin forms produce the same class map. Exposed for direct testing. */ export declare function transformCssModule(source: string, filePath: string): CssModuleResult; /** * The CSS Modules Bun plugin. `"dom"` → the `.module.css` import becomes the class map AND emits the * scoped stylesheet as a virtual `?nifra-css-module` module that `Bun.build`'s CSS bundler folds into * the app stylesheet. `"ssr"` → the class map only (no CSS; the scoped names match the client build). * Tolerates a trailing `?query` on the path (dev servers append one to bust Bun's import cache). */ export declare function cssModulesBunPlugin(generate: "dom" | "ssr"): BunPlugin; //# sourceMappingURL=css-modules.d.ts.map