Repository navigation
v0.6.0
Summary
System CSS is now a semantic artifact that Vanity owns by identity, instead of something inherited from whichever style module happened to evaluate first. That fixes missing token declarations across package boundaries and multi-page builds, and brings matching corrections to how identities are derived, how artifacts are published, and how the dev server recovers from a failed evaluation.
A design system can also live in one file now, and module roles are enforced at the file boundary with a diagnostic instead of a silent rewrite.
Upgrading
If you ship or consume a design system as build JavaScript plus a portable JSON artifact, rebuild it. Each of the four identities now derives from exactly the facts that projection owns, so an artifact generated before 0.6.0 disagrees with a 0.6.0 build and the strict reader rejects the pair, naming the package and the identities that differ. A normal build regenerates everything. There is no migration format and no code change to make, and the vanity.system/2 discriminator is unchanged.
Rebuild published design-system packages before consuming them from a 0.6.0 app. Compatibility identity changed, so a package built with 0.5.x and an application built with 0.6.0 will not be recognized as compatible.
Stored runtime snapshots keep working. A snapshot serialized before 0.6.0 carries the older runtime schema identity; reconciliation matches it by semantic address and reports a VANITY_RUNTIME_SCHEMA_MISMATCH note rather than failing. Snapshots produced and consumed within one deploy are unaffected.
Everyone else upgrades with no action. If your system module exports something that is neither the system nor a value taken from it, you will get a new build error naming the export and the one-line fix — see Added below.
Added
-
VANITY_APP_EXPORT_IN_SYSTEM_MODULEreports an application export that cannot travel with a system module. Application code receives a generated projection of that module, so an unrelated export has nowhere to go. The diagnostic names the file, the offending exports, your own system export name, and the fix — move the declaration into any other module and import it normally. It needs no Vanity configuration. Type-only exports are unaffected. -
VANITY_ARTIFACT_TARGET_INVALIDreplaces a bare failure when something other than a regular file occupies an artifact path, and names the path to clear.
Changed
-
A named rule's description is documentation only. Editing a description updates the manifest and leaves CSS bytes, CSS identity, compatibility identity, runtime identity, file mtimes, and the HMR channel untouched. Rule names and order remain structural; selectors, declarations, layers, and registrations stay in the projections that own them.
-
An omitted named-rule layer resolves to the system's global rule layer —
resetwhen declared, otherwise the first declared layer — and that resolved layer and order now drive sorting, emission, and identity alike. An omitted layer therefore behaves exactly like writing the effective default, and rules with equal layer and order keep registration order. Previously an omitted layer could be sorted as one thing and emitted as another. -
CSS identity preserves declaration order, inside named rules as well as between them, along with nested selectors, at-rules, and fallback arrays.
{ margin, marginTop }and{ marginTop, margin }produce different top margins, so they now receive different identities instead of sharing a stylesheet. -
Runtime schema identity now covers the conditions and layers an application projection exposes. Two systems whose generated modules expose different static application semantics can no longer share one runtime backing. This matches the documented runtime-schema contract.
-
Module roles hold at the file boundary. Vanity projects a system module for application graphs; it never rewrites your source to make one file serve two roles. Ordinary modules and pure re-export barrels pass through your bundler untouched, so objects keep reference identity, functions stay callable, and live bindings stay live.
Fixed
-
The documented one-file system now works in application code. A module can export its consolidated system alongside values taken from it, and serve as your
compiler.systementry:// src/design/ds.ts export const ds = createSystem() .addTokens({ color: { brand: '#635bff' } }) .consolidate({ prefix: 'app' }) export const { class: cls, rules, t } = ds
Style modules always handled this. Application modules did not: the generated projection matched exports by name, so a renamed destructure like
class: clswas silently dropped and importingclsfrom application code failed. Exports are now matched by identity against the evaluated system, so any name you choose resolves — including throughautoImports: { shared: '$system' }. Splitting the system and its authoring barrel across files remains fully supported. -
Token declarations no longer go missing when the system lives outside the app root. A system reached through a workspace package, an export map, a symlink, or an authoring barrel emitted its custom properties into whichever stylesheet the first style module happened to produce. A second page could then link rules referencing variables that were never declared. System CSS is now projected on its own, before any style can consume it, and every style keeps an edge to each system it reaches. This also resolves the case where two independent entry points — two HTML documents, or two extension pages — disagreed about which one carried the token layer.
-
A style module that throws no longer takes the system stylesheet with it. The failed evaluation used to consume the system's one-time emission and discard it, leaving every later style — and the repaired module itself — with no token declarations for the life of the dev server.
-
A failed evaluation no longer leaks its scope. File scope, captures, reference counters, and diagnostic sources are restored on both success and failure, so a repaired style, a plain system import, and the no-plugin misuse diagnostic all behave correctly afterwards without restarting the server.
-
Pointing
compiler.systemat a symlinked path no longer blames your code. Configuring it throughnode_moduleswhile imports resolved to the real file producedVANITY_SYSTEM_IN_STYLE_MODULEagainst a correct system module. Configured entries now resolve through your bundler, and the configured spelling, resolved module, authored source, CSS identity, virtual module, and browser URL are tracked as separate facts. -
Source-shipping packages keep their names and diagnostics. A
*.css.tsoutside the app root fell back to a filename-derived class name and lost source-local diagnostics. Authoring modules are now instrumented by role, whether linked from a workspace or installed undernode_modules. -
A barrel no longer overwrites the export namespace of the module it re-exports.
export { ds as theme } from './system'now servesthemefrom the barrel anddsfrom the leaf, sharing one runtime backing, in build, browser, and SSR graphs alike. -
HMR works under a non-root
base. Module-graph lookups, HMR payload paths, and browser request URLs are distinct protocols; the public base is applied only at the browser boundary. A token edit underbase: '/app/'now reaches the page instead of silently leaving the old computed value. -
Artifact publication is failure-atomic. A later write failure or a superseded generation no longer leaves files from a rejected candidate at accepted paths; already-replaced files are restored and temporary files are cleaned up. This is atomic within the running process, not against power loss.
-
Shared system CSS survives losing one owner. Two systems with the same CSS identity share a stylesheet; removing or replacing one no longer deletes the other's CSS, and a stylesheet is retired only once no owner and no in-flight transition still needs it. Updating equivalent owners together no longer reports a false namespace collision.
-
A CSS-identity change now reaches every page that uses it. A value edit that changes the identity switches each importer to the new virtual module and retires the old one, so an obsolete stylesheet can no longer win the cascade from a stale tag.