Follow-up to #309, which made every target emit a starter theme derived from the live capture
(sampled colors, fonts, radii, breakpoints from the DOM).
Deriving from a screenshot-and-DOM sample is a guess. When a repo is available it declares its theme
exactly, and reading it beats inferring it: the real token names, the real scale, the values the team
actually chose rather than whatever the homepage happened to render.
The constraint
At parity migrate time the target repo does not exist — creating it is the point of the
command. The only repo available is --source. So this is "read the source's declared theme", not
"read the target's".
That is still worth it: a migration usually keeps the brand, so the source's tokens are the right
starting values for the target's token names.
Detection, by source stack
| source |
where the theme lives |
deco-fresh |
tailwind.config.ts (theme.extend), and/or a Theme section in .deco/blocks/*.json |
vtex-io |
per-app CSS handles + styles/configs/*.json — no single theme file |
| FastStore v4 repo |
src/themes/** SCSS with the --fs-* tokens already named |
live-only |
nothing — the capture heuristic stays the only option |
So it is per-source detection feeding the existing per-target emitters, which is a clean shape: the
SourceInventory gains an optional theme, and buildXTheme prefers it over the captured
ThemeBundle field by field.
Worth deciding first
- Merge or replace? A source theme may declare 3 colors while the capture found 12. Field-level
preference (declared wins, captured fills gaps) is probably right, but it means the output mixes
two provenances — which should be visible in the file's header comment, not silent.
- Parsing
tailwind.config.ts is not free. It is TypeScript that can import and compute. A
regex gets the common case and lies on the rest; evaluating it means running untrusted code from
the source repo. Reading a Deco Theme block (plain JSON) is safe and probably covers the deco
sites that matter most — maybe start there and treat Tailwind config as out of scope.
Why it matters beyond fidelity
The captured theme is also what feeds the report's swatches, so a wrong primary colour shows up in
the client-facing artifact. Reading the declared value fixes both at once.
Follow-up to #309, which made every target emit a starter theme derived from the live capture
(sampled colors, fonts, radii, breakpoints from the DOM).
Deriving from a screenshot-and-DOM sample is a guess. When a repo is available it declares its theme
exactly, and reading it beats inferring it: the real token names, the real scale, the values the team
actually chose rather than whatever the homepage happened to render.
The constraint
At
parity migratetime the target repo does not exist — creating it is the point of thecommand. The only repo available is
--source. So this is "read the source's declared theme", not"read the target's".
That is still worth it: a migration usually keeps the brand, so the source's tokens are the right
starting values for the target's token names.
Detection, by source stack
deco-freshtailwind.config.ts(theme.extend), and/or a Theme section in.deco/blocks/*.jsonvtex-iostyles/configs/*.json— no single theme filesrc/themes/**SCSS with the--fs-*tokens already namedlive-onlySo it is per-source detection feeding the existing per-target emitters, which is a clean shape: the
SourceInventorygains an optionaltheme, andbuildXThemeprefers it over the capturedThemeBundlefield by field.Worth deciding first
preference (declared wins, captured fills gaps) is probably right, but it means the output mixes
two provenances — which should be visible in the file's header comment, not silent.
tailwind.config.tsis not free. It is TypeScript that can import and compute. Aregex gets the common case and lies on the rest; evaluating it means running untrusted code from
the source repo. Reading a Deco Theme block (plain JSON) is safe and probably covers the deco
sites that matter most — maybe start there and treat Tailwind config as out of scope.
Why it matters beyond fidelity
The captured theme is also what feeds the report's swatches, so a wrong primary colour shows up in
the client-facing artifact. Reading the declared value fixes both at once.