Builds the CSS bundle, writes the cache, registers HTTP routes, and hooks into
http:response:before β from that point on, the CSS bundle, anti-FOUC script,
and theme.js are automatically injected into every HTML response.
themeAssets() in templates is optional.
Option
Type
Description
Default
root
string
Base directory β controls where src/themes/ is discovered
process.cwd()
force
boolean
Ignore cache and rebuild the bundle
false
init() is idempotent β subsequent calls are ignored.
href()
1
theme.href();
2
// β '/_theme/css/xpulse.css'
URL of the bundled CSS (base + components + all themes, minified).
scriptHref()
1
theme.scriptHref();
2
// β '/_theme/theme.js'
URL of the browser runtime script (theme toggle, token editor).
current()
1
theme.current();
2
// β 'dark'
Current default theme from config (theme.default in xpulse.json).
available()
1
theme.available();
2
// β ['dark', 'light']
All themes discovered in the bundle via [data-theme="..."] selectors.
allowed()
1
theme.allowed();
2
// β ['dark', 'light']
Subset of available(), filtered by theme.allow in xpulse.json.
When theme.allow is empty or not set, returns all available themes.
has(name)
1
theme.has('dark'); // β true
2
theme.has('foo'); // β false
Checks whether a theme is known in the bundle.
set(name)
1
theme.set('light'); // β true
2
theme.set('foo'); // β false (unknown or not allowed)
Sets the current theme. Returns false if the theme is unknown or not in allowed().
toggle()
1
theme.toggle();
Toggles between the two allowed themes. Returns false if allowed() does not have exactly 2 entries.
Optional: <link rel="stylesheet" href="/_theme/app.css"> if an app theme exists
Inline anti-FOUC script (sets data-theme and theme-* class in <head> before first paint)
<script defer src="/_theme/theme.js">
`themeSwitcher()`
1
{% themeSwitcher() %}
Renders nothing if allowed() contains only one theme.
With exactly dark + light β compact moon/sun toggle button.
With more than 2 themes β <select> dropdown.
`themeTokenEditor()`
1
{% themeTokenEditor() %}
Live editor for selected :root tokens. Sets CSS custom properties directly
in the browser and persists overrides in localStorage.
Discovery
Theme names are extracted from the bundled CSS via regex:
1
[data-theme="dark"] β 'dark'
2
[data-theme="light"] β 'light'
CSS source files are bundled in this order:
1
1. public/css/base.css
2
2. public/css/components/*.css (via @import in components.css)
3
3. public/css/themes/*.css (built-in themes)
4
4. src/themes/*.css (app overrides, optional)
Caching
The bundle is cached at var/cache/theme/xpulse.css.
Always skipped in dev mode (NODE_ENV !== 'production')
init({ force: true }) bypasses the cache
Configurable via theme.cache in xpulse.json
1
{
2
"theme":{
3
"cache":{
4
"enabled":true,
5
"ttl":0
6
}
7
}
8
}
ttl: 0 means no expiry. ttl: 3600 invalidates the cache after 1 hour.