vite_plugin_fuz_css.ts view source
"/* generated by vite_plugin_fuz_css */" import {FUZ_CSS_BANNER} from '@fuzdev/fuz_css/vite_plugin_fuz_css.js'; Banner comment at the top and bottom of generated CSS output.
Vite plugin for fuz_css CSS generation.
Uses Vite's transform hook to extract CSS classes from source files
as they're processed, including node_modules dependencies. In bundled
mode (the default) it also resolves the base reset and theme variables,
emitting only the rules, elements, and variables the source actually uses -
including the var(--*) references of imported CSS files, like a
dependency's stylesheet.
Generates CSS on-demand via virtual module with HMR support.
In dev it eagerly pre-scans project sources at server startup so the first
served CSS is complete (see prescan), and extracts everything else as
the dev server transforms it - a pre-bundled dependency by way of the
source files its sourcemap lists, or as its bundled code when those can't
be read. CSS that changes while a page is still loading can't be
hot-updated into it, because the virtual module hasn't evaluated yet to
accept the update. So each client reports when it evaluates the module,
and the server answers with an update if that client holds code a refetch
would replace.
In build the generated CSS depends on every module's transform, so the
virtual module loads as a placeholder rule and the build finishes it
afterwards. renderChunk renders the CSS and restates the placeholder with
a hash of it, so the stylesheet Vite emits - and each chunk whose name
depends on that stylesheet's - gets a filename that changes when the
generated CSS does. generateBundle then splices the CSS in at the
placeholder's position (see css_placeholder_splice.ts), in whichever of
two passes the stylesheets exist for. A code-split build has them all by
then, so the first pass - at the default order, ahead of every other
plugin - finishes them and those plugins' generateBundle hooks read the
generated CSS. With build.cssCodeSplit: false (the build.lib default)
Vite emits the single stylesheet in its own generateBundle, so a second
pass at order: 'post' finishes it. An environment that emits no assets,
like a plain build.ssr, may have no stylesheet to finish.
The build's passes and the dev server's evaluation report each need a
different position in the plugin order, so vite_plugin_fuz_css returns
several plugin objects - pass its result to plugins as is. List it after
any plugin that rewrites CSS in its transform hook: the build restates
the placeholder from the text its build-only object saw, so what a plugin
listed later does to the virtual module's CSS (wrapping it in a layer,
say) applies in dev and is lost in build. PostCSS and lightningcss always
apply.
@example
// vite.config.ts
import {defineConfig} from 'vite';
import jsx from 'acorn-jsx';
import {vite_plugin_fuz_css} from '@fuzdev/fuz_css/vite_plugin_fuz_css.ts';
export default defineConfig({
plugins: [
vite_plugin_fuz_css({
acorn_plugins: [jsx()],
}),
],
});4 declarations
vite_plugin_fuz_css.ts view source
"/* generated by vite_plugin_fuz_css */" import {FUZ_CSS_BANNER} from '@fuzdev/fuz_css/vite_plugin_fuz_css.js'; Banner comment at the top and bottom of generated CSS output.
vite_plugin_fuz_css.ts view source
internal
Exported for its tests.
(id: string): string import {to_extraction_id} from '@fuzdev/fuz_css/vite_plugin_fuz_css.js'; Converts a Vite module id to the id its extraction is keyed by, dropping a
query made only of Vite's cache-busting parameters - the v version hash
the dev server gives a dependency's URL and the t HMR timestamp. Such an
id is the file itself, so it's filtered, parsed, cached, and deleted as the
plain path, sharing one entry with the same file's SSR transform and
pre-scan.
Any other query is kept, because it names a different module than the
file: Foo.svelte?svelte&type=style&lang.css is the component's CSS, and
?raw, ?url, and ?worker ids carry a generated wrapper rather than
the file's source.
ida resolved module id, as transform receives it
stringstring the id without its query when that query only busts a cache, otherwise id unchanged
vite_plugin_fuz_css.ts view source
(options?: VitePluginFuzCssOptions): Plugin<any>[] import {vite_plugin_fuz_css} from '@fuzdev/fuz_css/vite_plugin_fuz_css.js'; Creates the fuz_css Vite plugin.
Extracts CSS classes from source files during Vite's transform phase
and generates optimized CSS via the virtual:fuz.css virtual module.
options{}Plugin<any>[]
the plugin as several objects sharing state, to pass to Vite's
plugins together: an enforce: 'pre' one that does the extraction, serves
the virtual module, and splices the build's CSS ahead of other plugins, a
build-only one positioned after Vite's CSS processing that completes the
build's stylesheets, and a serve-only enforce: 'post' one that adds the
evaluation report to the virtual module's client code
vite_plugin_fuz_css.ts view source
VitePluginFuzCssOptions import type {VitePluginFuzCssOptions} from '@fuzdev/fuz_css/vite_plugin_fuz_css.js'; Options for the fuz_css Vite plugin. Extends the shared base options with Vite-specific options.
prescan?Dev-only eager pre-scan of source files at server startup.
Extraction state accumulates from Vite's transform hook, so without a
pre-scan the first CSS served on a cold start includes only the files
the module graph happened to visit first, and the rest arrives as
corrective HMR updates while the page loads. The pre-scan extracts every
file passing filter_file under the given directories, plus the Vite
root's index.html, before the virtual module is first served, so the
initial CSS is complete. Warm starts are cheap via the extraction cache.
true scans src under the Vite root; false disables; an array gives
custom directories (resolved against the Vite root unless absolute).
The root index.html is included whichever directories are given: the
dev server serves it without running transform on it, so nothing else
would extract it. Pre-scanned files are kept current - one the watcher
reports added or changed is extracted again, whether or not any module
imports it.
node_modules dependencies are never pre-scanned, and neither are project
files outside the scanned directories. They're extracted when the dev
server first transforms them, which is during the first load of a page
that uses them, so that page's CSS is completed by an update a moment
after it's first served rather than up front (or by the next reload,
with server.hmr or server.ws off).
What dev and build extract differs at the edges:
src/app.html among them), including ones imported only
with ?raw - the pre-scan reads them from disk, where a build
extracts just the modules it transforms; and a pre-bundled dependency
that's extracted from its bundled code while filter_file rejects
the files it ships (the default filter skips .mjs), which a build
doesn't extract at allindex.html; a module of a pre-bundled dependency that the
pre-bundler dropped as unused, such as one holding nothing but a
@fuz-classes comment; and the comment hints and static Svelte
class attributes of a pre-bundled dependency whose sourcemap is
missing or names files that aren't installed, which is extracted
from its bundled code insteadtype boolean | string[]
true