Skip to content

v4.3.0 — theme/engine split complete

Latest

Choose a tag to compare

@thunpisit thunpisit released this 18 Aug 15:12
· 2 commits to main since this release
242a377

v4.3.0 — the theme/engine split is complete (#174)

This release finishes the work that makes one promise to every downstream repo: upgrading upstream never costs you your theme again.

Why upgrades used to lose your UI

Your custom look lived in forked engine files — the layout, the homepage, checkout. Every git merge upstream/main hit conflicts in those exact files, and every resolution either dropped your brand (upstream side) or silently dropped upstream's fixes (your side). Measured on a real fork: the homepage alone diverged 23 → 592 lines.

What replaces that, as of this release

Your theme now lives in code upstream never touches, registered through seams the engine promises to keep:

Your customization Where it lives now
Header / footer setChrome({ header, footer }) — components in src/lib/deployment/
Homepage setChrome({ home }) — the route file is engine-owned; your markup is a registered component
Checkout fields (e.g. Thai tax invoice) registerCheckoutSlots() — three slots, contribution flows into billingAddress end-to-end
Fonts, meta, verification tags src/app.head.html — injected on every page, deployment-owned
Colors, radius, display font, logo /admin/settings theme tokens — operator config, zero code
Everything else visual README.md, wrangler.toml, src/lib/deployment/** are fork-side by contract

All registrations go in src/lib/plugins/registrations.ts (loaded by server and client — registering elsewhere causes SSR-then-snap-back; see chrome.ts).

The guarantee, in writing and in CI

  • docs/THEME-CONTRACT.md — the full contract: every seam above, the props your components receive, Paraglide message-key stability (a shipped key is never removed within a MAJOR), which files are fork-side, and the route add/add precedence rule.
  • THEME_CONTRACT_VERSION = 1.0.0 (src/lib/theme-contract.ts) — removals of any contract surface are a MAJOR bump; additions are MINOR.
  • pnpm run guard:contract runs in CI on every commit: if an engine change deletes anything a theme may depend on (a slot, a props field, a message key, a building-block component), the build fails with the item named until the MAJOR is bumped explicitly. A contract break can no longer ship as a quiet refactor.

How to upgrade a themed fork to this release

  1. Merge: git fetch upstream && git merge upstream/main. Expect conflicts ONLY in files you own (README.md, wrangler.toml, and — one last time — any engine file you forked for looks). Keep your side for the first two.
  2. For each engine file you forked visually (homepage, header, footer): move your markup into src/lib/deployment/YourComponent.svelte, take upstream's version of the engine file, and register yours:
    // src/lib/deployment/chrome.ts
    import { setChrome } from "$lib/components/www/chrome";
    import YourHome from "./YourHome.svelte";
    setChrome({ home: YourHome });
    then import "$lib/deployment/chrome"; from src/lib/plugins/registrations.ts.
  3. Move colors/radius/fonts you had hard-coded in CSS into /admin/settings theme tokens where possible.
  4. Run the gate: pnpm test && pnpm run guard:contract && pnpm build.
  5. Done — your next upstream merge should be conflict-free. The reference fork (codustry/khaopad-example) did exactly this migration in this release cycle, and its Step-7 sync was the first fully mechanical, zero-conflict merge in the project's history.

Worked example: khaopad-example@cc1e16b is the complete homepage migration, commit-sized.

Also in this release

  • Step 5 (#187) — theme tokens as operator config: background/foreground/accent colors, radius, display font, all strictly validated server-side and at render (nothing style-breaking can reach the style attribute), SSR-first so no flash of default theme.
  • Step 6 (#188) — homepage behind the seam, SSR-verified byte-identical for unthemed installs.
  • Step 7 (#189) — the contract: docs, version constant, CI guard (floor semantics, negative-tested).
  • From the v4.2.x line already on main: tax-entity fields persist end-to-end on billing addresses (#171/#185), credential endpoints rate-limited (#182/#184/#186), /admin/profile for self-service password change (#178).

1007 tests; CSS-inventory, head, and contract guards all green; deployed and verified on the reference deployment.