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 ## 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 ## 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 Source Files Build Steps Output
───────────── ─────────── ────── ───────────── ─────────── ──────
src/App.svelte ─┐ 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 │ src/lib/api.js ─┘ + TailwindCSS JIT │
+ vite-plugin-singlefile ▼ + vite-plugin-singlefile ▼
gzip compression gzip compression (level 9)
dist/index.html.gz (~4-8kB) dist/index.html.gz (16kB)
ESP32 Flash (SPIFFS/LittleFS) 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: 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 2. A script converts the gzipped file to a C `const uint8_t[]` array
3. The array is compiled into the firmware binary 3. The array is compiled into the firmware binary
4. OTA flashes one binary that includes both firmware and frontend 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 ## 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`.