svelteesp32 1.13.1 → 1.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +253 -424
- package/dist/commandLine.d.ts +2 -0
- package/dist/commandLine.js +32 -2
- package/dist/cppCode.d.ts +1 -1
- package/dist/cppCode.js +242 -16
- package/dist/cppCodeEspIdf.d.ts +1 -1
- package/dist/cppCodeEspIdf.js +31 -6
- package/dist/index.d.ts +7 -1
- package/dist/index.js +10 -4
- package/package.json +9 -9
package/README.md
CHANGED
|
@@ -1,135 +1,125 @@
|
|
|
1
|
-
#
|
|
1
|
+
# svelteesp32 
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
# Convert Svelte (or React/Angular/Vue) JS application to serve it from ESP32/ESP8266 webserver
|
|
6
|
-
|
|
7
|
-
### Forget SPIFFS and LittleFS now
|
|
8
|
-
|
|
9
|
-
I often make small to medium-sized microcontroller solutions that run on ESP32 or ESP8266. If a web interface is needed, I create a Svelte application. The Svelte application is practically served by the ESP32/ESP8266.
|
|
10
|
-
|
|
11
|
-
In order to be able to easily update OTA, it is important - from the users' point of view - that the update file **consists of one file**. I can't use the SPIFFS/LittleFS solution for this. It is necessary that the WebUI files are included inline in the Arduino or PlatformIO c++ code.
|
|
12
|
-
|
|
13
|
-
This npm package provides a solution for **inserting any JS client application into the ESP web server** (PsychicHttp and also ESPAsyncWebServer (https://github.com/ESP32Async/ESPAsyncWebServer) and ESP-IDF available, PsychicHttp is the default). For this, JS, html, css, font, assets, etc. files must be converted to binary byte array. Npm mode is easy to use and easy to **integrate into your CI/CD pipeline**.
|
|
3
|
+
### Embed Any Web App in Your ESP32 — One Binary, Zero Filesystem Hassle
|
|
14
4
|
|
|
15
|
-
**
|
|
5
|
+
**Turn your Svelte, React, Angular, or Vue frontend into a single C++ header file.** Serve beautiful web interfaces directly from ESP32/ESP8266 flash memory with automatic gzip compression, ETag caching, and seamless OTA updates.
|
|
16
6
|
|
|
17
|
-
|
|
18
|
-
| --------------------- | --------------------------------------- | ---------------------------------------- |
|
|
19
|
-
| **Single Binary OTA** | ✓ Everything embedded in firmware | ✗ Requires separate partition upload |
|
|
20
|
-
| **Gzip Compression** | ✓ Automatic build-time (>15% reduction) | Manual or runtime compression |
|
|
21
|
-
| **ETag Support** | ✓ Built-in MD5 ETags with 304 responses | Manual implementation required |
|
|
22
|
-
| **CI/CD Integration** | ✓ npm package, simple build step | Complex with upload_fs tools |
|
|
23
|
-
| **Memory Efficiency** | Flash only (PROGMEM/const arrays) | Flash partition + filesystem overhead |
|
|
24
|
-
| **Performance** | Direct byte array serving | Filesystem read overhead |
|
|
25
|
-
| **Setup Complexity** | Include header, call init function | Partition setup, upload tools, handlers |
|
|
26
|
-
|
|
27
|
-
**When to use:**
|
|
28
|
-
|
|
29
|
-
- **SvelteESP32**: Single-binary OTA updates, CI/CD pipelines, static web content that doesn't change at runtime
|
|
30
|
-
- **SPIFFS/LittleFS**: Dynamic content, user-uploadable files, configuration that changes at runtime
|
|
31
|
-
|
|
32
|
-
> Starting with version v1.13.0, RC files support npm package variable interpolation
|
|
7
|
+
[Changelog](CHANGELOG.md)
|
|
33
8
|
|
|
34
|
-
|
|
9
|
+
---
|
|
35
10
|
|
|
36
|
-
|
|
11
|
+
## Why SvelteESP32?
|
|
37
12
|
|
|
38
|
-
|
|
13
|
+
**The problem:** Traditional approaches like SPIFFS and LittleFS require separate partition uploads, complex OTA workflows, and manual compression. Your users end up managing multiple files, and your CI/CD pipeline becomes a mess.
|
|
39
14
|
|
|
40
|
-
|
|
15
|
+
**The solution:** SvelteESP32 compiles your entire web application into a single C++ header file. One firmware binary. One OTA update. Done.
|
|
41
16
|
|
|
42
|
-
|
|
17
|
+
### Key Benefits
|
|
43
18
|
|
|
44
|
-
|
|
19
|
+
- **Single Binary OTA** — Everything embedded in firmware. No partition juggling, no separate uploads.
|
|
20
|
+
- **Automatic Optimization** — Build-time gzip compression with intelligent thresholds (>1KB, >15% reduction).
|
|
21
|
+
- **Smart Caching** — Built-in SHA256 ETags deliver HTTP 304 responses, slashing bandwidth on constrained devices.
|
|
22
|
+
- **CI/CD Ready** — Simple npm package that slots into any build pipeline.
|
|
23
|
+
- **Zero Runtime Overhead** — Data served directly from flash. No filesystem reads, no RAM allocation.
|
|
24
|
+
- **4 Web Server Engines** — PsychicHttp V1/V2, ESPAsyncWebServer, and native ESP-IDF supported.
|
|
45
25
|
|
|
46
|
-
|
|
26
|
+
---
|
|
47
27
|
|
|
48
|
-
|
|
28
|
+
## SvelteESP32 vs Traditional Filesystem
|
|
49
29
|
|
|
50
|
-
|
|
30
|
+
| Feature | SvelteESP32 | SPIFFS / LittleFS |
|
|
31
|
+
| --------------------- | --------------------------------- | ---------------------------------------- |
|
|
32
|
+
| **Single Binary OTA** | ✓ Everything in firmware | ✗ Separate partition upload required |
|
|
33
|
+
| **Gzip Compression** | ✓ Automatic at build time | Manual or runtime compression |
|
|
34
|
+
| **ETag Support** | ✓ Built-in SHA256 + 304 responses | Manual implementation required |
|
|
35
|
+
| **CI/CD Integration** | ✓ One npm command | Complex upload_fs tooling |
|
|
36
|
+
| **Memory Efficiency** | Flash only (PROGMEM/const arrays) | Filesystem partition + overhead |
|
|
37
|
+
| **Performance** | Direct byte array serving | Filesystem read latency |
|
|
38
|
+
| **Setup Complexity** | Include header, call one function | Partition tables, upload tools, handlers |
|
|
51
39
|
|
|
52
|
-
|
|
40
|
+
**Best for:** Single-binary OTA, CI/CD pipelines, static web UIs that ship with firmware.
|
|
53
41
|
|
|
54
|
-
|
|
42
|
+
**Consider SPIFFS/LittleFS for:** User-uploadable files, runtime-editable configs, dynamic content.
|
|
55
43
|
|
|
56
|
-
|
|
44
|
+
---
|
|
57
45
|
|
|
58
|
-
|
|
46
|
+
## Quick Start
|
|
59
47
|
|
|
60
|
-
|
|
61
|
-
|
|
48
|
+
```bash
|
|
49
|
+
npm install -D svelteesp32
|
|
50
|
+
```
|
|
62
51
|
|
|
63
|
-
|
|
52
|
+
After building your frontend (Vite/Rollup/Webpack):
|
|
64
53
|
|
|
65
|
-
|
|
54
|
+
```bash
|
|
55
|
+
npx svelteesp32 -e psychic -s ./dist -o ./esp32/svelteesp32.h --etag=true
|
|
56
|
+
```
|
|
66
57
|
|
|
67
|
-
|
|
58
|
+
Include in your ESP32 project:
|
|
68
59
|
|
|
69
|
-
```
|
|
70
|
-
#
|
|
71
|
-
|
|
60
|
+
```c
|
|
61
|
+
#include <PsychicHttp.h>
|
|
62
|
+
#include "svelteesp32.h"
|
|
72
63
|
|
|
73
|
-
|
|
74
|
-
npm run test:watch
|
|
64
|
+
PsychicHttpServer server;
|
|
75
65
|
|
|
76
|
-
|
|
77
|
-
|
|
66
|
+
void setup() {
|
|
67
|
+
server.listen(80);
|
|
68
|
+
initSvelteStaticFiles(&server);
|
|
69
|
+
}
|
|
78
70
|
```
|
|
79
71
|
|
|
80
|
-
**
|
|
81
|
-
|
|
82
|
-
- `commandLine.ts`: 84.56% - CLI argument parsing and validation
|
|
83
|
-
- `file.ts`: 100% - File operations and duplicate detection
|
|
84
|
-
- `cppCode.ts`: 96.62% - C++ code generation and templates
|
|
85
|
-
- `consoleColor.ts`: 100% - Console output utilities
|
|
72
|
+
**That's it.** Your entire web app is now embedded and ready to serve.
|
|
86
73
|
|
|
87
|
-
|
|
74
|
+
---
|
|
88
75
|
|
|
89
|
-
|
|
76
|
+
## What's New
|
|
90
77
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
78
|
+
- **v1.15.0** — `--base-path` for multiple frontends (e.g., `/admin`, `/app`)
|
|
79
|
+
- **v1.13.0** — npm package variable interpolation in RC files
|
|
80
|
+
- **v1.12.0** — RC file configuration support
|
|
81
|
+
- **v1.11.0** — File exclusion patterns
|
|
82
|
+
- **v1.9.0** — Native ESP-IDF engine
|
|
83
|
+
- **v1.5.0** — PsychicHttp V2 support
|
|
94
84
|
|
|
95
|
-
|
|
96
|
-
npm run format:fix
|
|
85
|
+
---
|
|
97
86
|
|
|
98
|
-
|
|
99
|
-
npm run lint:check
|
|
87
|
+
## Requirements
|
|
100
88
|
|
|
101
|
-
|
|
102
|
-
npm
|
|
89
|
+
- Node.js >= 20
|
|
90
|
+
- npm >= 9
|
|
103
91
|
|
|
104
|
-
|
|
105
|
-
npm run fix
|
|
106
|
-
```
|
|
92
|
+
---
|
|
107
93
|
|
|
108
|
-
|
|
94
|
+
## Installation & Usage
|
|
109
95
|
|
|
110
|
-
|
|
96
|
+
### Install
|
|
111
97
|
|
|
112
98
|
```bash
|
|
113
99
|
npm install -D svelteesp32
|
|
114
100
|
```
|
|
115
101
|
|
|
116
|
-
|
|
102
|
+
### Generate Header File
|
|
103
|
+
|
|
104
|
+
Choose your web server engine:
|
|
117
105
|
|
|
118
106
|
```bash
|
|
119
|
-
|
|
120
|
-
npx svelteesp32 -e psychic -s
|
|
107
|
+
# PsychicHttpServer (recommended for ESP32)
|
|
108
|
+
npx svelteesp32 -e psychic -s ./dist -o ./esp32/svelteesp32.h --etag=true
|
|
121
109
|
|
|
122
|
-
|
|
123
|
-
npx svelteesp32 -e psychic2 -s
|
|
110
|
+
# PsychicHttpServer V2
|
|
111
|
+
npx svelteesp32 -e psychic2 -s ./dist -o ./esp32/svelteesp32.h --etag=true
|
|
124
112
|
|
|
125
|
-
|
|
126
|
-
npx svelteesp32 -e async -s
|
|
113
|
+
# ESPAsyncWebServer (ESP32 + ESP8266)
|
|
114
|
+
npx svelteesp32 -e async -s ./dist -o ./esp32/svelteesp32.h --etag=true
|
|
127
115
|
|
|
128
|
-
|
|
129
|
-
npx svelteesp32 -e espidf -s
|
|
116
|
+
# Native ESP-IDF
|
|
117
|
+
npx svelteesp32 -e espidf -s ./dist -o ./esp32/svelteesp32.h --etag=true
|
|
130
118
|
```
|
|
131
119
|
|
|
132
|
-
|
|
120
|
+
### Build Output
|
|
121
|
+
|
|
122
|
+
Watch your files get optimized in real-time:
|
|
133
123
|
|
|
134
124
|
```
|
|
135
125
|
[assets/index-KwubEIf-.js] ✓ gzip used (38850 -> 12547 = 32%)
|
|
@@ -142,82 +132,62 @@ During the **translation process**, the processed file details are visible with
|
|
|
142
132
|
../../../Arduino/EspSvelte/svelteesp32.h 842kB size
|
|
143
133
|
```
|
|
144
134
|
|
|
145
|
-
|
|
135
|
+
**Automatic optimizations:**
|
|
146
136
|
|
|
147
|
-
-
|
|
148
|
-
-
|
|
149
|
-
-
|
|
137
|
+
- Gzip level 9 compression when beneficial (>1KB, >15% size reduction)
|
|
138
|
+
- Duplicate file detection via SHA256 hashing
|
|
139
|
+
- Smart skip of pre-compressed files (.gz, .br) when originals exist
|
|
150
140
|
|
|
151
|
-
|
|
141
|
+
### ESP32 Integration
|
|
152
142
|
|
|
153
|
-
|
|
154
|
-
...
|
|
143
|
+
**PsychicHttpServer (Recommended)**
|
|
155
144
|
|
|
145
|
+
```c
|
|
156
146
|
#include <PsychicHttp.h>
|
|
157
147
|
#include "svelteesp32.h"
|
|
158
148
|
|
|
159
149
|
PsychicHttpServer server;
|
|
160
150
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
void setup()
|
|
164
|
-
{
|
|
165
|
-
...
|
|
166
|
-
|
|
151
|
+
void setup() {
|
|
167
152
|
server.listen(80);
|
|
168
|
-
|
|
169
|
-
initSvelteStaticFiles(&server);
|
|
153
|
+
initSvelteStaticFiles(&server); // One line. Done.
|
|
170
154
|
}
|
|
171
155
|
```
|
|
172
156
|
|
|
173
|
-
|
|
157
|
+
**ESPAsyncWebServer**
|
|
174
158
|
|
|
175
159
|
```c
|
|
176
|
-
...
|
|
177
|
-
|
|
178
160
|
#include <ESPAsyncWebServer.h>
|
|
179
161
|
#include "svelteesp32.h"
|
|
180
162
|
|
|
181
163
|
AsyncWebServer server(80);
|
|
182
164
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
void setup()
|
|
186
|
-
{
|
|
187
|
-
...
|
|
188
|
-
|
|
165
|
+
void setup() {
|
|
189
166
|
initSvelteStaticFiles(&server);
|
|
190
|
-
|
|
191
167
|
server.begin();
|
|
192
168
|
}
|
|
193
169
|
```
|
|
194
170
|
|
|
195
|
-
|
|
171
|
+
**Native ESP-IDF**
|
|
196
172
|
|
|
197
173
|
```c
|
|
198
|
-
...
|
|
199
|
-
|
|
200
174
|
#include <esp_http_server.h>
|
|
201
175
|
#include "svelteesp32.h"
|
|
202
176
|
|
|
203
177
|
httpd_handle_t server = NULL;
|
|
204
178
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
void app_main()
|
|
208
|
-
{
|
|
209
|
-
...
|
|
210
|
-
|
|
179
|
+
void app_main() {
|
|
211
180
|
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
|
|
212
181
|
httpd_start(&server, &config);
|
|
213
|
-
|
|
214
182
|
initSvelteStaticFiles(server);
|
|
215
183
|
}
|
|
216
184
|
```
|
|
217
185
|
|
|
218
|
-
|
|
186
|
+
Working examples: [Arduino/PlatformIO](demo/esp32) | [ESP-IDF](demo/esp32idf)
|
|
187
|
+
|
|
188
|
+
### What Gets Generated
|
|
219
189
|
|
|
220
|
-
The
|
|
190
|
+
The generated header file includes everything your ESP needs:
|
|
221
191
|
|
|
222
192
|
```c
|
|
223
193
|
//engine: PsychicHttpServer
|
|
@@ -240,14 +210,33 @@ const uint8_t datagzip_assets_index_KwubEIf__js[12547] = {0x1f, 0x8b, 0x8, 0x0,
|
|
|
240
210
|
const uint8_t datagzip_assets_index_Soe6cpLA_css[5368] = {0x1f, 0x8b, 0x8, 0x0, 0x0, ...
|
|
241
211
|
const char * etag_assets_index_KwubEIf__js = "387b88e345cc56ef9091...";
|
|
242
212
|
const char * etag_assets_index_Soe6cpLA_css = "d4f23bc45ef67890ab12...";
|
|
213
|
+
|
|
214
|
+
// File manifest for runtime introspection
|
|
215
|
+
struct SVELTEESP32_FileInfo {
|
|
216
|
+
const char* path;
|
|
217
|
+
uint32_t size;
|
|
218
|
+
uint32_t gzipSize;
|
|
219
|
+
const char* etag;
|
|
220
|
+
const char* contentType;
|
|
221
|
+
};
|
|
222
|
+
const SVELTEESP32_FileInfo SVELTEESP32_FILES[] = {
|
|
223
|
+
{ "/assets/index-KwubEIf-.js", 38850, 12547, etag_assets_index_KwubEIf__js, "text/javascript" },
|
|
224
|
+
{ "/assets/index-Soe6cpLA.css", 32494, 5368, etag_assets_index_Soe6cpLA_css, "text/css" },
|
|
225
|
+
...
|
|
226
|
+
};
|
|
227
|
+
const size_t SVELTEESP32_FILE_COUNT = sizeof(SVELTEESP32_FILES) / sizeof(SVELTEESP32_FILES[0]);
|
|
243
228
|
...
|
|
244
229
|
|
|
230
|
+
// File served hook - override with your own implementation for metrics/logging
|
|
231
|
+
extern "C" void __attribute__((weak)) SVELTEESP32_onFileServed(const char* path, int statusCode) {}
|
|
232
|
+
|
|
245
233
|
void initSvelteStaticFiles(PsychicHttpServer * server) {
|
|
246
234
|
server->on("/assets/index-KwubEIf-.js", HTTP_GET, [](PsychicRequest * request) {
|
|
247
235
|
if (request->hasHeader("If-None-Match") &&
|
|
248
236
|
request->header("If-None-Match").equals(etag_assets_index_KwubEIf__js)) {
|
|
249
237
|
PsychicResponse response304(request);
|
|
250
238
|
response304.setCode(304);
|
|
239
|
+
SVELTEESP32_onFileServed("/assets/index-KwubEIf-.js", 304);
|
|
251
240
|
return response304.send();
|
|
252
241
|
}
|
|
253
242
|
|
|
@@ -257,23 +246,7 @@ void initSvelteStaticFiles(PsychicHttpServer * server) {
|
|
|
257
246
|
response.addHeader("Cache-Control", "no-cache");
|
|
258
247
|
response.addHeader("ETag", etag_assets_index_KwubEIf__js);
|
|
259
248
|
response.setContent(datagzip_assets_index_KwubEIf__js, 12547);
|
|
260
|
-
|
|
261
|
-
});
|
|
262
|
-
|
|
263
|
-
server->on("/assets/index-Soe6cpLA.css", HTTP_GET, [](PsychicRequest * request) {
|
|
264
|
-
if (request->hasHeader("If-None-Match") &&
|
|
265
|
-
request->header("If-None-Match").equals(etag_assets_index_Soe6cpLA_css)) {
|
|
266
|
-
PsychicResponse response304(request);
|
|
267
|
-
response304.setCode(304);
|
|
268
|
-
return response304.send();
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
PsychicResponse response(request);
|
|
272
|
-
response.setContentType("text/css");
|
|
273
|
-
response.addHeader("Content-Encoding", "gzip");
|
|
274
|
-
response.addHeader("Cache-Control", "no-cache");
|
|
275
|
-
response.addHeader("ETag", etag_assets_index_Soe6cpLA_css);
|
|
276
|
-
response.setContent(datagzip_assets_index_Soe6cpLA_css, 5368);
|
|
249
|
+
SVELTEESP32_onFileServed("/assets/index-KwubEIf-.js", 200);
|
|
277
250
|
return response.send();
|
|
278
251
|
});
|
|
279
252
|
|
|
@@ -281,393 +254,249 @@ void initSvelteStaticFiles(PsychicHttpServer * server) {
|
|
|
281
254
|
}
|
|
282
255
|
```
|
|
283
256
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
Four web server engines are supported:
|
|
287
|
-
|
|
288
|
-
- **`-e psychic`** (default): PsychicHttpServer V1 - Fast ESP32-only server using ESP-IDF internally. Recommended for ESP32 projects.
|
|
289
|
-
- **`-e psychic2`**: PsychicHttpServer V2 - Updated version with improved API
|
|
290
|
-
- **`-e async`**: ESPAsyncWebServer (https://github.com/ESP32Async/ESPAsyncWebServer) - Popular async server supporting both ESP32 and ESP8266/ESP8285
|
|
291
|
-
- **`-e espidf`**: Native ESP-IDF web server - For projects using ESP-IDF framework directly (not Arduino)
|
|
257
|
+
---
|
|
292
258
|
|
|
293
|
-
|
|
259
|
+
## Supported Web Server Engines
|
|
294
260
|
|
|
295
|
-
|
|
261
|
+
| Engine | Flag | Best For | Platform |
|
|
262
|
+
| --------------------- | ------------- | ---------------------------- | --------------- |
|
|
263
|
+
| **PsychicHttp V1** | `-e psychic` | Maximum performance | ESP32 only |
|
|
264
|
+
| **PsychicHttp V2** | `-e psychic2` | Modern API + performance | ESP32 only |
|
|
265
|
+
| **ESPAsyncWebServer** | `-e async` | Cross-platform compatibility | ESP32 + ESP8266 |
|
|
266
|
+
| **Native ESP-IDF** | `-e espidf` | Pure ESP-IDF projects | ESP32 only |
|
|
296
267
|
|
|
297
|
-
|
|
268
|
+
**Recommendation:** For ESP32-only projects, use PsychicHttpServer for the fastest, most stable experience.
|
|
298
269
|
|
|
299
|
-
|
|
270
|
+
**Note:** For PsychicHttp, configure `server.config.max_uri_handlers` to match your file count.
|
|
300
271
|
|
|
301
|
-
|
|
272
|
+
---
|
|
302
273
|
|
|
303
|
-
|
|
274
|
+
## Features
|
|
304
275
|
|
|
305
|
-
|
|
276
|
+
### Automatic Gzip Compression
|
|
306
277
|
|
|
307
|
-
|
|
278
|
+
Your JS, CSS, and HTML files are automatically compressed at build time — not on the ESP32. Files are gzipped when they're >1KB and achieve >15% size reduction.
|
|
308
279
|
|
|
309
|
-
|
|
280
|
+
- **Enabled by default** — disable with `--gzip=false`
|
|
281
|
+
- **Compiler mode** — use `--gzip=compiler` and control via `-D SVELTEESP32_ENABLE_GZIP` in PlatformIO
|
|
310
282
|
|
|
311
|
-
|
|
283
|
+
### Smart ETag Caching
|
|
312
284
|
|
|
313
|
-
|
|
285
|
+
Reduce bandwidth dramatically with HTTP 304 "Not Modified" responses. When a browser has a cached file, the ESP32 sends just a status code instead of the entire file — perfect for bandwidth-constrained IoT devices.
|
|
314
286
|
|
|
315
|
-
|
|
287
|
+
- **Enable with** `--etag=true` (recommended)
|
|
288
|
+
- **Minimal overhead** — adds ~1-3% code size for significant bandwidth savings
|
|
289
|
+
- **Compiler mode** — use `--etag=compiler` and control via `-D SVELTEESP32_ENABLE_ETAG`
|
|
316
290
|
|
|
317
|
-
|
|
291
|
+
All four engines support full ETag validation.
|
|
318
292
|
|
|
319
|
-
### Cache
|
|
293
|
+
### Browser Cache Control
|
|
320
294
|
|
|
321
|
-
|
|
295
|
+
Fine-tune how browsers cache your content:
|
|
322
296
|
|
|
323
|
-
|
|
297
|
+
- **Default:** `no-cache` — browsers always validate with server (ETag check)
|
|
298
|
+
- **Long-term caching:** `--cachetime=86400` — cache for 24 hours without any server requests
|
|
324
299
|
|
|
325
|
-
###
|
|
300
|
+
### Automatic Index Handling
|
|
326
301
|
|
|
327
|
-
|
|
302
|
+
Your `index.html` is automatically served at the root URL — just like any web server. Visit `http://esp32.local/` and your app loads.
|
|
328
303
|
|
|
329
|
-
**
|
|
330
|
-
|
|
331
|
-
**Skipping Validation**: If you're building an API-only application (REST endpoints without a web UI) or using a different entry point (e.g., `main.html`), you can skip this validation with the `--no-index-check` flag:
|
|
304
|
+
**API-only projects?** Skip index validation with `--no-index-check`:
|
|
332
305
|
|
|
333
306
|
```bash
|
|
334
|
-
# API-only application (no web UI)
|
|
335
|
-
npx svelteesp32 -e psychic -s ./dist -o ./output.h --no-index-check
|
|
336
|
-
|
|
337
|
-
# Custom entry point (users must visit /main.html explicitly)
|
|
338
307
|
npx svelteesp32 -e psychic -s ./dist -o ./output.h --no-index-check
|
|
339
308
|
```
|
|
340
309
|
|
|
341
310
|
### File Exclusion
|
|
342
311
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
#### Basic Usage
|
|
312
|
+
Keep source maps, docs, and test files out of your firmware:
|
|
346
313
|
|
|
347
314
|
```bash
|
|
348
|
-
#
|
|
349
|
-
npx svelteesp32 -
|
|
350
|
-
|
|
351
|
-
# Exclude documentation files
|
|
352
|
-
npx svelteesp32 -e psychic -s ./dist -o ./output.h --exclude="*.md"
|
|
353
|
-
|
|
354
|
-
# Exclude multiple file types (comma-separated)
|
|
355
|
-
npx svelteesp32 -e psychic -s ./dist -o ./output.h --exclude="*.map,*.md,*.txt"
|
|
315
|
+
# Single pattern
|
|
316
|
+
npx svelteesp32 -s ./dist -o ./output.h --exclude="*.map"
|
|
356
317
|
|
|
357
|
-
#
|
|
358
|
-
npx svelteesp32 -
|
|
359
|
-
|
|
360
|
-
# Exclude entire directories
|
|
361
|
-
npx svelteesp32 -e psychic -s ./dist -o ./output.h --exclude="test/**/*"
|
|
362
|
-
|
|
363
|
-
# Combine multiple approaches
|
|
364
|
-
npx svelteesp32 -e psychic -s ./dist -o ./output.h --exclude="*.map,*.md" --exclude="docs/**/*"
|
|
318
|
+
# Multiple patterns
|
|
319
|
+
npx svelteesp32 -s ./dist -o ./output.h --exclude="*.map,*.md,test/**/*"
|
|
365
320
|
```
|
|
366
321
|
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
The exclude patterns use standard glob syntax:
|
|
370
|
-
|
|
371
|
-
- `*.map` - Match all files ending with `.map`
|
|
372
|
-
- `**/*.test.js` - Match all `.test.js` files in any directory
|
|
373
|
-
- `test/**/*` - Match all files in the `test` directory and subdirectories
|
|
374
|
-
- `.DS_Store` - Match specific filename
|
|
375
|
-
|
|
376
|
-
#### Default Exclusions
|
|
377
|
-
|
|
378
|
-
By default, the following system and development files are automatically excluded:
|
|
322
|
+
**Default exclusions:** `.DS_Store`, `Thumbs.db`, `.git`, `.svn`, `*.swp`, `*~`, `.gitignore`, `.gitattributes`
|
|
379
323
|
|
|
380
|
-
|
|
381
|
-
- `Thumbs.db` (Windows thumbnail cache)
|
|
382
|
-
- `.git` (Git directory)
|
|
383
|
-
- `.svn` (SVN directory)
|
|
384
|
-
- `*.swp` (Vim swap files)
|
|
385
|
-
- `*~` (Backup files)
|
|
386
|
-
- `.gitignore` (Git ignore file)
|
|
387
|
-
- `.gitattributes` (Git attributes file)
|
|
388
|
-
|
|
389
|
-
Custom exclude patterns are added to these defaults.
|
|
390
|
-
|
|
391
|
-
#### Exclusion Output
|
|
392
|
-
|
|
393
|
-
When files are excluded, you'll see a summary in the build output:
|
|
324
|
+
Build output shows exactly what's excluded:
|
|
394
325
|
|
|
395
326
|
```
|
|
396
|
-
Excluded
|
|
327
|
+
Excluded 3 file(s):
|
|
397
328
|
- assets/index.js.map
|
|
398
329
|
- assets/vendor.js.map
|
|
399
330
|
- README.md
|
|
400
|
-
- docs/guide.md
|
|
401
|
-
- test/unit.test.js
|
|
402
331
|
```
|
|
403
332
|
|
|
404
|
-
|
|
333
|
+
### Multiple Frontends (Base Path)
|
|
405
334
|
|
|
406
|
-
|
|
335
|
+
Serve multiple web apps from one ESP32 using URL prefixes:
|
|
407
336
|
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
337
|
+
```bash
|
|
338
|
+
npx svelteesp32 -s ./admin-dist -o ./admin.h --base-path=/admin
|
|
339
|
+
npx svelteesp32 -s ./user-dist -o ./user.h --base-path=/app
|
|
340
|
+
```
|
|
411
341
|
|
|
412
342
|
```c
|
|
413
|
-
|
|
414
|
-
#include "
|
|
343
|
+
#include "admin.h" // Serves at /admin/*
|
|
344
|
+
#include "user.h" // Serves at /app/*
|
|
415
345
|
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
346
|
+
void setup() {
|
|
347
|
+
server.listen(80);
|
|
348
|
+
initSvelteStaticFiles_admin(&server);
|
|
349
|
+
initSvelteStaticFiles_user(&server);
|
|
350
|
+
server.on("/api/data", HTTP_GET, handleApiData);
|
|
351
|
+
}
|
|
420
352
|
```
|
|
421
353
|
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
```c
|
|
425
|
-
...
|
|
426
|
-
#include "svelteesp32.h"
|
|
354
|
+
**Rules:** Must start with `/`, no trailing slash, no double slashes.
|
|
427
355
|
|
|
428
|
-
|
|
429
|
-
#error Missing index file
|
|
430
|
-
#endif
|
|
431
|
-
...
|
|
432
|
-
```
|
|
356
|
+
### C++ Build-Time Validation
|
|
433
357
|
|
|
434
|
-
|
|
358
|
+
Catch configuration issues at compile time with generated defines:
|
|
435
359
|
|
|
436
360
|
```c
|
|
437
|
-
...
|
|
438
361
|
#include "svelteesp32.h"
|
|
439
362
|
|
|
440
|
-
#if
|
|
441
|
-
#error
|
|
363
|
+
#if SVELTEESP32_COUNT != 5
|
|
364
|
+
#error Unexpected file count - check your build
|
|
442
365
|
#endif
|
|
443
|
-
...
|
|
444
|
-
```
|
|
445
|
-
|
|
446
|
-
You can use the following c++ directives at the project level if you want to configure the usage there: `SVELTEESP32_ENABLE_ETAG` and `SVELTEESP32_ENABLE_GZIP`. (Do not forget `--etag=compiler` or `--gzip=compiler` command line arg!)
|
|
447
|
-
|
|
448
|
-
### Command line options
|
|
449
|
-
|
|
450
|
-
| Option | Description | default |
|
|
451
|
-
| ------------------ | ------------------------------------------------------------------------------------ | ----------------------- |
|
|
452
|
-
| `-s` | **Source dist folder contains compiled web files** | (required) |
|
|
453
|
-
| `-e` | The engine for which the include file is created (psychic/psychic2/async/espidf) | psychic |
|
|
454
|
-
| `-o` | Generated output file with path | `svelteesp32.h` |
|
|
455
|
-
| `--exclude` | Exclude files matching glob pattern (repeatable or comma-separated) | Default system files |
|
|
456
|
-
| `--etag` | Use ETag header for cache (true/false/compiler) | false |
|
|
457
|
-
| `--cachetime` | Override no-cache response with a max-age=\<cachetime\> response (seconds) | 0 |
|
|
458
|
-
| `--gzip` | Compress content with gzip (true/false/compiler) | true |
|
|
459
|
-
| `--created` | Include creation time in generated header | false |
|
|
460
|
-
| `--version` | Include a version string in generated header, e.g. `--version=v$npm_package_version` | '' |
|
|
461
|
-
| `--espmethod` | Name of generated initialization method | `initSvelteStaticFiles` |
|
|
462
|
-
| `--define` | Prefix of c++ defines (e.g., SVELTEESP32_COUNT) | `SVELTEESP32` |
|
|
463
|
-
| `--config` | Use custom RC file path | `.svelteesp32rc.json` |
|
|
464
|
-
| `--no-index-check` | Skip validation for index.html/index.htm (for API-only or custom entry points) | false |
|
|
465
|
-
| `-h` | Show help | |
|
|
466
|
-
|
|
467
|
-
### Configuration File
|
|
468
|
-
|
|
469
|
-
You can store frequently-used options in a configuration file to avoid repeating command line arguments. This is especially useful for CI/CD pipelines and team collaboration.
|
|
470
|
-
|
|
471
|
-
#### Quick Start
|
|
472
|
-
|
|
473
|
-
Create `.svelteesp32rc.json` in your project directory:
|
|
474
|
-
|
|
475
|
-
```json
|
|
476
|
-
{
|
|
477
|
-
"engine": "psychic",
|
|
478
|
-
"sourcepath": "./dist",
|
|
479
|
-
"outputfile": "./esp32/include/svelteesp32.h",
|
|
480
|
-
"etag": "true",
|
|
481
|
-
"gzip": "true",
|
|
482
|
-
"cachetime": 86400,
|
|
483
|
-
"exclude": ["*.map", "*.md"]
|
|
484
|
-
}
|
|
485
|
-
```
|
|
486
|
-
|
|
487
|
-
Then simply run:
|
|
488
|
-
|
|
489
|
-
```bash
|
|
490
|
-
npx svelteesp32
|
|
491
|
-
```
|
|
492
|
-
|
|
493
|
-
No command line arguments needed!
|
|
494
|
-
|
|
495
|
-
#### Search Locations
|
|
496
|
-
|
|
497
|
-
The tool automatically searches for `.svelteesp32rc.json` in:
|
|
498
|
-
|
|
499
|
-
1. Current working directory
|
|
500
|
-
2. User home directory
|
|
501
|
-
|
|
502
|
-
Or specify a custom location:
|
|
503
|
-
|
|
504
|
-
```bash
|
|
505
|
-
npx svelteesp32 --config=.svelteesp32rc.prod.json
|
|
506
|
-
```
|
|
507
|
-
|
|
508
|
-
#### Configuration Reference
|
|
509
|
-
|
|
510
|
-
All CLI options can be specified in the RC file using long-form property names:
|
|
511
|
-
|
|
512
|
-
| RC Property | CLI Flag | Type | Example |
|
|
513
|
-
| -------------- | ------------------ | ------- | ------------------------------------------------ |
|
|
514
|
-
| `engine` | `-e` | string | `"psychic"`, `"psychic2"`, `"async"`, `"espidf"` |
|
|
515
|
-
| `sourcepath` | `-s` | string | `"./dist"` |
|
|
516
|
-
| `outputfile` | `-o` | string | `"./output.h"` |
|
|
517
|
-
| `etag` | `--etag` | string | `"true"`, `"false"`, `"compiler"` |
|
|
518
|
-
| `gzip` | `--gzip` | string | `"true"`, `"false"`, `"compiler"` |
|
|
519
|
-
| `cachetime` | `--cachetime` | number | `86400` |
|
|
520
|
-
| `created` | `--created` | boolean | `true`, `false` |
|
|
521
|
-
| `version` | `--version` | string | `"v1.0.0"` |
|
|
522
|
-
| `espmethod` | `--espmethod` | string | `"initSvelteStaticFiles"` |
|
|
523
|
-
| `define` | `--define` | string | `"SVELTEESP32"` |
|
|
524
|
-
| `exclude` | `--exclude` | array | `["*.map", "*.md"]` |
|
|
525
|
-
| `noIndexCheck` | `--no-index-check` | boolean | `true`, `false` |
|
|
526
|
-
|
|
527
|
-
#### CLI Override
|
|
528
366
|
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
# Use RC settings but override etag
|
|
533
|
-
npx svelteesp32 --etag=false
|
|
534
|
-
|
|
535
|
-
# Use RC settings but add different exclude pattern
|
|
536
|
-
npx svelteesp32 --exclude="*.txt"
|
|
367
|
+
#ifndef SVELTEESP32_FILE_INDEX_HTML
|
|
368
|
+
#error Missing index.html - frontend build failed?
|
|
369
|
+
#endif
|
|
537
370
|
```
|
|
538
371
|
|
|
539
|
-
|
|
372
|
+
**Available defines:** `SVELTEESP32_COUNT`, `SVELTEESP32_SIZE`, `SVELTEESP32_SIZE_GZIP`, `SVELTEESP32_FILE_*`, `SVELTEESP32_*_FILES`
|
|
540
373
|
|
|
541
|
-
|
|
374
|
+
### Runtime File Manifest
|
|
542
375
|
|
|
543
|
-
|
|
544
|
-
# Development build
|
|
545
|
-
npx svelteesp32 --config=.svelteesp32rc.dev.json
|
|
376
|
+
Query embedded files at runtime for logging, diagnostics, or API endpoints:
|
|
546
377
|
|
|
547
|
-
|
|
548
|
-
|
|
378
|
+
```c
|
|
379
|
+
// List all embedded files
|
|
380
|
+
for (size_t i = 0; i < SVELTEESP32_FILE_COUNT; i++) {
|
|
381
|
+
const auto& f = SVELTEESP32_FILES[i];
|
|
382
|
+
Serial.printf("%s (%d bytes, gzip: %d)\n", f.path, f.size, f.gzipSize);
|
|
383
|
+
}
|
|
549
384
|
```
|
|
550
385
|
|
|
551
|
-
|
|
386
|
+
Each file entry includes: `path`, `size`, `gzipSize`, `etag`, `contentType`
|
|
552
387
|
|
|
553
|
-
|
|
388
|
+
### Request Hook (Metrics & Logging)
|
|
554
389
|
|
|
555
|
-
|
|
556
|
-
- **RC file has exclude**: Replaces defaults with RC patterns
|
|
557
|
-
- **CLI has --exclude**: Replaces RC patterns (or defaults if no RC)
|
|
390
|
+
Track every request with zero overhead when unused (weak linkage):
|
|
558
391
|
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
392
|
+
```c
|
|
393
|
+
extern "C" void SVELTEESP32_onFileServed(const char* path, int statusCode) {
|
|
394
|
+
Serial.printf("[HTTP] %s -> %d\n", path, statusCode);
|
|
395
|
+
if (statusCode == 304) cacheHits++;
|
|
396
|
+
}
|
|
564
397
|
```
|
|
565
398
|
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
To keep defaults, explicitly list them in your RC file:
|
|
399
|
+
Called for every response (200 = content served, 304 = cache hit).
|
|
569
400
|
|
|
570
|
-
|
|
571
|
-
{
|
|
572
|
-
"exclude": [".DS_Store", "Thumbs.db", ".git", "*.map", "*.md"]
|
|
573
|
-
}
|
|
574
|
-
```
|
|
401
|
+
---
|
|
575
402
|
|
|
576
|
-
|
|
403
|
+
## CLI Reference
|
|
577
404
|
|
|
578
|
-
|
|
405
|
+
| Option | Description | Default |
|
|
406
|
+
| ------------------ | ------------------------------------------------- | ----------------------- |
|
|
407
|
+
| `-s` | Source folder with compiled web files | (required) |
|
|
408
|
+
| `-e` | Web server engine (psychic/psychic2/async/espidf) | `psychic` |
|
|
409
|
+
| `-o` | Output header file path | `svelteesp32.h` |
|
|
410
|
+
| `--etag` | ETag caching (true/false/compiler) | `false` |
|
|
411
|
+
| `--gzip` | Gzip compression (true/false/compiler) | `true` |
|
|
412
|
+
| `--exclude` | Exclude files by glob pattern | System files |
|
|
413
|
+
| `--base-path` | URL prefix for all routes | (none) |
|
|
414
|
+
| `--cachetime` | Cache-Control max-age in seconds | `0` |
|
|
415
|
+
| `--version` | Version string in header | (none) |
|
|
416
|
+
| `--define` | C++ define prefix | `SVELTEESP32` |
|
|
417
|
+
| `--espmethod` | Init function name | `initSvelteStaticFiles` |
|
|
418
|
+
| `--config` | Custom RC file path | `.svelteesp32rc.json` |
|
|
419
|
+
| `--no-index-check` | Skip index.html validation | `false` |
|
|
420
|
+
| `-h` | Show help | |
|
|
579
421
|
|
|
580
|
-
|
|
422
|
+
---
|
|
581
423
|
|
|
582
|
-
|
|
424
|
+
## Configuration File
|
|
583
425
|
|
|
584
|
-
|
|
426
|
+
Store your settings in `.svelteesp32rc.json` for zero-argument builds:
|
|
585
427
|
|
|
586
428
|
```json
|
|
587
|
-
// .svelteesp32rc.json
|
|
588
429
|
{
|
|
589
430
|
"engine": "psychic",
|
|
590
|
-
"version": "v$npm_package_version",
|
|
591
|
-
"define": "$npm_package_name",
|
|
592
431
|
"sourcepath": "./dist",
|
|
593
|
-
"outputfile": "./
|
|
432
|
+
"outputfile": "./esp32/svelteesp32.h",
|
|
433
|
+
"etag": "true",
|
|
434
|
+
"gzip": "true",
|
|
435
|
+
"exclude": ["*.map", "*.md"]
|
|
594
436
|
}
|
|
595
437
|
```
|
|
596
438
|
|
|
597
|
-
|
|
439
|
+
Then just run:
|
|
598
440
|
|
|
599
|
-
```
|
|
600
|
-
|
|
601
|
-
"name": "my-esp32-app",
|
|
602
|
-
"version": "2.1.0"
|
|
603
|
-
}
|
|
441
|
+
```bash
|
|
442
|
+
npx svelteesp32
|
|
604
443
|
```
|
|
605
444
|
|
|
606
|
-
|
|
445
|
+
### npm Variable Interpolation
|
|
446
|
+
|
|
447
|
+
Sync versions and names automatically from your `package.json`:
|
|
607
448
|
|
|
608
449
|
```json
|
|
609
450
|
{
|
|
610
|
-
"version": "
|
|
611
|
-
"define": "
|
|
451
|
+
"version": "v$npm_package_version",
|
|
452
|
+
"define": "$npm_package_name"
|
|
612
453
|
}
|
|
613
454
|
```
|
|
614
455
|
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
You can access nested package.json fields using underscores:
|
|
456
|
+
With `package.json` containing `"version": "2.1.0"`, this becomes `"version": "v2.1.0"`.
|
|
618
457
|
|
|
619
|
-
|
|
620
|
-
// package.json
|
|
621
|
-
{
|
|
622
|
-
"name": "myapp",
|
|
623
|
-
"repository": {
|
|
624
|
-
"type": "git",
|
|
625
|
-
"url": "https://github.com/user/repo.git"
|
|
626
|
-
}
|
|
627
|
-
}
|
|
458
|
+
### Multiple Environments
|
|
628
459
|
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
"version": "$npm_package_repository_type"
|
|
632
|
-
}
|
|
633
|
-
// Results in: "version": "git"
|
|
460
|
+
```bash
|
|
461
|
+
npx svelteesp32 --config=.svelteesp32rc.prod.json
|
|
634
462
|
```
|
|
635
463
|
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
Combine multiple variables in a single field:
|
|
464
|
+
CLI arguments always override RC file values.
|
|
639
465
|
|
|
640
|
-
|
|
641
|
-
{
|
|
642
|
-
"version": "$npm_package_name-v$npm_package_version-release"
|
|
643
|
-
}
|
|
644
|
-
// Results in: "my-esp32-app-v2.1.0-release"
|
|
645
|
-
```
|
|
466
|
+
---
|
|
646
467
|
|
|
647
|
-
|
|
468
|
+
## FAQ
|
|
648
469
|
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
- Unknown variables are left unchanged (e.g., `$npm_package_nonexistent` stays as-is)
|
|
470
|
+
**How large can my web app be?**
|
|
471
|
+
With gzip compression, 3-4MB asset directories work comfortably. That's enough for a full-featured SPA.
|
|
652
472
|
|
|
653
|
-
**
|
|
473
|
+
**Does this use RAM or Flash?**
|
|
474
|
+
Flash only. Data is stored in program memory (PROGMEM on ESP8266, const arrays on ESP32), leaving your heap and stack free for application logic.
|
|
654
475
|
|
|
655
|
-
|
|
656
|
-
-
|
|
657
|
-
- **CI/CD Integration:** Reusable RC files across projects with different package names
|
|
476
|
+
**Why is the .h file so large?**
|
|
477
|
+
The text representation (comma-separated bytes) is larger than binary. Check `SVELTEESP32_SIZE_GZIP` for actual flash usage.
|
|
658
478
|
|
|
659
|
-
|
|
479
|
+
**Does compilation take forever?**
|
|
480
|
+
No. Large headers compile in seconds, and incremental builds skip recompilation if your frontend hasn't changed.
|
|
660
481
|
|
|
661
|
-
|
|
482
|
+
**Can frontend and firmware teams work separately?**
|
|
483
|
+
Absolutely. Frontend builds the app, runs svelteesp32, commits the header. Firmware team includes it and ships. Version sync via npm variables keeps everyone aligned.
|
|
662
484
|
|
|
663
|
-
|
|
485
|
+
---
|
|
664
486
|
|
|
665
|
-
|
|
487
|
+
## Development
|
|
666
488
|
|
|
667
|
-
|
|
489
|
+
```bash
|
|
490
|
+
npm run build # Build TypeScript
|
|
491
|
+
npm run test # Run unit tests
|
|
492
|
+
npm run test:watch # Watch mode
|
|
493
|
+
npm run fix # Fix formatting & linting
|
|
494
|
+
```
|
|
668
495
|
|
|
669
|
-
|
|
496
|
+
---
|
|
670
497
|
|
|
671
|
-
|
|
498
|
+
**Ready to ship your web UI in a single binary?**
|
|
672
499
|
|
|
673
|
-
|
|
500
|
+
```bash
|
|
501
|
+
npm install -D svelteesp32
|
|
502
|
+
```
|