4.1 KiB
4.1 KiB
Spec: Remove Juice & Simplify Preview Module
Date: 2026-06-23 Status: approved
Goal
Remove multi-email-client simulation (Gmail/Outlook) from the preview module, eliminate the juice CSS-inlining dependency, and rewrite the dev server in pure Go with SSE-based live reload.
Motivation
- Multi-client CSS simulation has diminishing value — modern email clients render consistently
juice+ Node.js adds complexity (npm install, node_modules, separate runtime)- The project already uses Go for all build tooling; a Node.js dev server is an outlier
- Simplifying to "Modern" and "Source" views covers the real use cases
Changes
1. Delete tools/server/ (entire directory)
Remove all Node.js artifacts:
inliner.mjs— juice CSS inlining + Gmail/Outlook CSS strippingserver.mjs— Express + WebSocket dev serverpackage.json/package-lock.jsonnode_modules/— all npm dependencies
2. Rewrite tools/cli/dev.go
- Remove Node.js dependency check
- Remove
exec.Command("node", "server.mjs")subprocess - Instead: create and start a pure Go HTTP server (calling into
tools/preview/server.go) - Keep the same CLI interface:
go run . dev [--port <port>]
3. New file: tools/preview/server.go
Pure Go dev server with:
- Static file serving — serve
preview/directory (index.html, rendered.js) - SSE endpoint (
GET /events) — Server-Sent Events for browser reload notifications - File watcher — poll
themes/every 500ms, compare mod times of.tmplfiles - On change detected — call
preview.RenderAll()directly (in-process, no subprocess), writerendered.js, broadcast SSEreloadevent - No external Go dependencies — uses
net/httpstdlib only
4. Modify preview/index.html
Frontend changes:
- Client selector — reduce from 4 options (Modern/Gmail/Outlook/Raw Source) to 2 (Modern/Source)
- Remove
renderedGmail/renderedOutlookvariables and all Gmail/Outlook JS logic - Simplify
getRendered()— always returnsrendered - Simplify
transform()— only handlessourcemode (HTML escaping) - Remove Client Simulation indicators panel (HTML section + JS in
updatePanel()) - Remove static-mode warning message ("Gmail / Outlook simulation is approximate...")
- Replace WebSocket with SSE (
new EventSource('/events')) - SSE reload handler — dynamically reload
rendered.jsonreloadevent, re-render iframe without losing current theme/template/viewport selection - Simplify
setDevMode()— remove multi-client disclaimer
5. Update AGENTS.md
- Remove references to Juice, Node.js, Gmail/Outlook variants
- Update dev server description to reflect pure Go implementation
Non-Changes
tools/preview/engine.go— template rendering engine unchangedtools/preview/funcs.go— template functions unchangedtools/preview/locale.go— locale data unchangedtools/config/— config loading unchangedtools/data/templates_config.json— unchangedtools/cli/preview.go— preview command unchangedtools/cli/commands.go— command registration unchanged- All theme
.tmplfiles — unchanged
Behavior
Static preview (open preview/index.html directly)
- Works via
file://protocol as before - Two view modes: Modern (rendered HTML in iframe) and Source (escaped HTML source)
- No dev-mode warnings needed
Dev mode (go run . dev)
go run . devstarts the Go HTTP server on port 3456 (configurable)- On startup: runs preview engine once, writes
rendered.js - Serves
preview/as static files - Watches
themes/for.tmplchanges (500ms polling) - On change: re-renders affected themes, updates
rendered.js, pushes SSE event - Browser auto-reloads preview content without page refresh (preserves UI state)
Constraints
- No new Go dependencies — SSE and file polling use stdlib only
- No Node.js requirement
preview/rendered.jsformat stays compatible:window.__RENDERED__,window.__REGISTRY__,window.__PARAMS__- Preview still works with
file://protocol (no server needed for basic use)