From a0789775727f34e912e7a34f4a086d205596d1d0 Mon Sep 17 00:00:00 2001 From: Patedam Date: Mon, 2 Mar 2026 21:29:57 -0500 Subject: [PATCH] docs: Document frontend technology choices for ESP32-S3, detailing the selection of Svelte, Vite, and TailwindCSS for a lightweight web UI. --- Provider/tdd/frontend_technology_choices.md | 87 +++++++++++++++++++-- 1 file changed, 81 insertions(+), 6 deletions(-) diff --git a/Provider/tdd/frontend_technology_choices.md b/Provider/tdd/frontend_technology_choices.md index 9081aab..05e35f3 100644 --- a/Provider/tdd/frontend_technology_choices.md +++ b/Provider/tdd/frontend_technology_choices.md @@ -7,7 +7,7 @@ ## 1. Goal -Create a lightweight web frontend for the ESP32-S3 Provider that displays system information and provides a reboot control. The frontend must compile to static files small enough to live in ESP32 flash memory (~4-8kB gzipped). +Create a lightweight web frontend for the ESP32-S3 Provider that displays system information and provides a reboot control. The frontend must compile to static files small enough to live in ESP32 flash memory. ## 2. Chosen Stack @@ -97,13 +97,13 @@ Although we don't use the framework, we adopt the same **proven patterns**: Source Files Build Steps Output ───────────── ─────────── ────── src/App.svelte ─┐ -src/app.css ├─→ Vite + Svelte Compiler ─→ dist/index.html (~15-25kB) +src/app.css ├─→ Vite + Svelte Compiler ─→ dist/index.html (47kB) src/lib/api.js ─┘ + TailwindCSS JIT │ + vite-plugin-singlefile ▼ - gzip compression + gzip compression (level 9) │ ▼ - dist/index.html.gz (~4-8kB) + dist/index.html.gz (16kB) │ ▼ ESP32 Flash (SPIFFS/LittleFS) @@ -125,7 +125,7 @@ This is handled via Vite's `.env.development` and `.env.production` files. The v When OTA updates are implemented, the frontend will be embedded into the firmware binary as a C header array: -1. `npm run build:esp32` → `dist/index.html.gz` (~4-8kB) +1. `npm run build:esp32` → `dist/index.html.gz` (~16kB) 2. A script converts the gzipped file to a C `const uint8_t[]` array 3. The array is compiled into the firmware binary 4. OTA flashes one binary that includes both firmware and frontend @@ -134,4 +134,79 @@ This avoids needing a separate SPIFFS partition for the frontend and ensures the ## 10. Summary -We chose **Svelte + TailwindCSS + Vite** because they are build-time tools that produce the smallest possible static output, ideal for ESP32 constraints. We build to a **single gzipped HTML file** of ~4-8kB. We did not adopt ESP32-SvelteKit because it requires PlatformIO/Arduino, which is incompatible with our native ESP-IDF project, and includes unnecessary complexity for our simple dashboard. +We chose **Svelte + TailwindCSS + Vite** because they are build-time tools that produce the smallest possible static output, ideal for ESP32 constraints. We build to a **single gzipped HTML file** of ~16kB. We did not adopt ESP32-SvelteKit because it requires PlatformIO/Arduino, which is incompatible with our native ESP-IDF project, and includes unnecessary complexity for our simple dashboard. + +--- + +## 11. Implementation Results + +*Added 2026-03-02 after implementation was completed.* + +### Final Build Output + +| File | Size | Notes | +|---|---|---| +| `dist/index.html` | **47.0 kB** | Single self-contained file (all JS + CSS inlined) | +| `dist/index.html.gz` | **16.1 kB** | Gzipped at max level 9 (65% reduction) | + +### Size Breakdown (before inlining) + +| Asset | Uncompressed | Gzipped | +|---|---|---| +| HTML shell | 0.4 kB | 0.3 kB | +| CSS (TailwindCSS JIT) | 12.4 kB | 3.2 kB | +| JS (Svelte compiled) | 34.9 kB | 13.5 kB | +| **Total** | **47.7 kB** | **17.0 kB** | + +The singlefile plugin reduces total size by ~0.8kB (removes multi-file boilerplate). Its main value is operational (one file, one HTTP request, no filesystem overhead). + +### File Structure + +``` +Provider/frontend/ +├── .env.development # VITE_API_BASE=http://ESP32_IP_HERE +├── .env.production # VITE_API_BASE= (empty, same-origin) +├── index.html # Vite entry point +├── package.json # npm scripts: dev, build, build:esp32 +├── vite.config.js # Svelte + TailwindCSS + singlefile plugins +├── scripts/ +│ └── gzip.js # Node.js gzip script (built-in zlib, no deps) +└── src/ + ├── main.js # Svelte mount point + ├── app.css # TailwindCSS v4 imports + @theme tokens + ├── App.svelte # Dashboard UI (system info, reboot button) + └── lib/ + └── api.js # API helpers (getSystemInfo, reboot) +``` + +### Dashboard Features + +- System info display: chip model, free heap, uptime, firmware version, connection type +- Reboot button with confirmation modal +- Auto-refresh polling every 5 seconds +- Four status states: loading, connected, offline, rebooting +- Dark theme with custom color tokens +- Fully responsive layout + +### npm Scripts + +| Script | Command | Purpose | +|---|---|---| +| `npm run dev` | `vite` | Dev server with HMR (for PC development) | +| `npm run build` | `vite build` | Production build (single `index.html`) | +| `npm run build:esp32` | `vite build && node scripts/gzip.js` | Build + gzip for ESP32 deployment | + +### Versions Used + +| Package | Version | +|---|---| +| Svelte | 5.45.2 | +| Vite | 7.3.1 | +| TailwindCSS | 4.2.1 | +| @tailwindcss/vite | 4.2.1 | +| vite-plugin-singlefile | 2.3.0 | + +### Known Issues + +- **W: drive**: Vite requires `resolve.preserveSymlinks: true` in `vite.config.js` because `W:` is a `subst` drive mapped to `C:\Dev\...`. Without this, the build fails with `fileName` path resolution errors. +- **ESP32 backend not yet implemented**: The frontend expects `GET /api/system/info` and `POST /api/system/reboot` endpoints. These need to be added to `main.cpp` using `esp_http_server`.