Files
iammiti99/themes/bonsai/docs/journals/2026-05-03-v0-2-release.md
T
tiennm99 698f39392f docs(journal): v0.2 release retro
Captures CSS specificity gotcha, Hugo jsonify-in-script trap, hardcoded SVG fill issue, and the modular-commit safety net learned from the same-day v0.1 → v0.2 cadence.
2026-05-03 12:43:21 +07:00

4.8 KiB

Bonsai v0.2: Same-Day Polish Release Caught CSS Specificity and Hugo's JSON Escape Trap

Date: 2026-05-03 20:15
Severity: Medium
Component: Theme toggle UI, schema.org markup, CSS cascade, SVG assets
Status: Resolved

What Happened

Shipped v0.2.0 same day as v0.1.0 (7 hours apart): 4 color theme presets (sakura/sumi/koi via CSS custom properties), schema.org Person JSON-LD, theme-toggle button with sun/moon icons, avatar initials fallback SVG. All 5 phases completed in ~6h. Tagged release; live demo + themes gallery live. No breaking changes — all features opt-in via params.

The Brutal Truth

Adding features that fast after a critical v0.1 release felt reckless but the modularity kept us honest. We caught two ugly bugs only because the screenshot review was rigorous. A CSS specificity silent failure sneaked into production; a Hugo templating anti-pattern almost shipped JSON garbage into <script> tags. Both were low-level enough to silently break on edge cases. The discipline of small additive commits meant rollback was one revert, not six.

Technical Details

  1. Hugo jsonify double-encodes inside <script> context — Hugo's auto-escape pipeline treats <script> block content as JavaScript string literal. Output {{ $payload | jsonify }} becomes "{\"@context\":...}" (stringified JSON string) instead of raw JSON. Fix: pipe through safeJS to mark output as safe for JS context: {{ $payload | jsonify | safeJS }}. Manifests as broken schema.org payloads when parsed by search crawlers.

  2. CSS specificity silent battle on .theme-toggle — .theme-toggle svg { display: block } (specificity 0,1,1) silently beat .theme-toggle__sun { display: none } (specificity 0,1,0). Both icons rendered at once, toggling did nothing visible. Caught only because screenshot diff showed two moons stacked. Fix: scope all per-icon rules under parent: .theme-toggle .theme-toggle__sun { display: none } to match the broader selector's context. Lesson: CSS specificity debugs invisibly.

  3. Hardcoded color in exampleSite/static/images/avatar.svg — vermilion fill="#8b3a2b" locked the avatar to one palette; theme toggle recolored the site but avatar stayed red. Removed avatar from exampleSite entirely to showcase the new initials fallback feature. Felt like a loss until we realized the demo got better — validates that initials auto-inherit palette accent and live-update on theme toggle.

  4. Small + additive release cadence builds confidence in rollback — v0.1 was large. v0.2 added 4 features in 5 commits. When specificity bug surfaced at final review, the fix was a 2-line CSS change in a single commit. If all v0.2 work were one megacommit, rollback would've nuked 6 hours of work. Discipline in commit granularity pays off.

Root Cause Analysis

  • Hugo template quirks aren't obvious from docs. jsonify works fine in template interpolation but breaks in <script>. Needed to test the actual rendered HTML, not just the template logic.
  • CSS cascade assumed matching specificity. Both selectors hit the toggle element; only one was checked. No linting caught this because both selectors are valid — the bug is order + specificity interaction.
  • Static assets assumed single-theme context. SVG fill attributes don't inherit from CSS custom properties by default. Should've validated asset reuse under theme toggle during phase 4 review.
  • Commit discipline was the real safety net. Each phase was one clean commit. Enabled fast iteration without fear of losing work.

Lessons Learned

  1. Test rendered HTML, not template output. For JSON-LD and <script> blocks, inspect the final HTML in DevTools. Auto-escape traps are invisible in template files.

  2. CSS specificity bugs hide best in visual tests. Automated CSS linting misses specificity collisions. Screenshot diffs catch them immediately.

  3. Static SVG assets don't theme well. If an SVG must recolor under theme toggle, either: remove the fill attribute and inherit from CSS, or generate it dynamically. Hardcoded fills are a gotcha.

  4. Same-day releases are only safe if phases are modular. v0.1→v0.2 worked because phases had minimal coupling. Try this with a monolithic feature and you're fighting merge conflicts and rollback chaos.

Next Steps

  • Monitor schema.org validation via Google Search Console (confirm JSON-LD is parsed correctly after safeJS fix).
  • Consider CSS specificity audit for all .theme-toggle__* variants before v0.3 (preventive).
  • For future static assets: add a validation step in screenshot capture that checks for hardcoded colors that don't inherit.
  • v0.3 candidates: layout variants (cards/grid), OG image generation, i18n setup. Keep the same cadence: small, additive, low blast radius.

Owner: @tiennm99
Timeline: Next release pending catalog PR #708 feedback