docs: Document frontend technology choices for ESP32-S3, detailing the selection of Svelte, Vite, and TailwindCSS for a lightweight web UI.

This commit is contained in:
2026-03-02 21:29:57 -05:00
parent 1d30773234
commit a078977572

View File

@@ -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`.