svelteesp32 1.14.0 → 1.16.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 CHANGED
@@ -1,135 +1,125 @@
1
- # `svelteesp32` ![image](https://badges.github.io/stability-badges/dist/stable.svg)
1
+ # svelteesp32 ![image](https://badges.github.io/stability-badges/dist/stable.svg)
2
2
 
3
- [Changelog](CHANGELOG.md)
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**.
14
-
15
- **Quick Comparison:**
3
+ ### Embed Any Web App in Your ESP32 — One Binary, Zero Filesystem Hassle
16
4
 
17
- | Feature | SvelteESP32 | Traditional Filesystem (SPIFFS/LittleFS) |
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 SHA256 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 |
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.
26
6
 
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
- > Starting with version v1.12.0, you can use RC file for configuration
9
+ ---
35
10
 
36
- > Starting with version v1.11.0, you can exclude files by pattern
11
+ ## Why SvelteESP32?
37
12
 
38
- > Starting with version v1.10.0, we reduced npm dependencies
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
- > Starting with version v1.9.0, code generator for esp-idf is available
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
- > Starting with version v1.8.0, use the new and maintained ESPAsyncWebserver available at https://github.com/ESP32Async/ESPAsyncWebServer
17
+ ### Key Benefits
43
18
 
44
- > Starting with version v1.7.0, with the cachetime command line option, you can set whether the browser can cache pages
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
- > Starting with version v1.6.0, mime-types package properly handles MIME types (application/javascript -> text/javascript)
26
+ ---
47
27
 
48
- > Starting with version v1.5.0, PsychicHttp v2 is also supported.
28
+ ## SvelteESP32 vs Traditional Filesystem
49
29
 
50
- > Version v1.4.0 has a breaking change! --no-gzip changed to --gzip. Starting with this version c++ compiler directives are available to setup operation in project level.
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
- > Starting with version v1.3.0, c++ defines can be used.
40
+ **Best for:** Single-binary OTA, CI/CD pipelines, static web UIs that ship with firmware.
53
41
 
54
- > Starting with version v1.2.0, ESP8266/ESP8285 is also supported.
42
+ **Consider SPIFFS/LittleFS for:** User-uploadable files, runtime-editable configs, dynamic content.
55
43
 
56
- > Starting with version v1.1.0, the ETag header is also supported.
44
+ ---
57
45
 
58
- ### Requirements
46
+ ## Quick Start
59
47
 
60
- - Node.js >= 20
61
- - npm >= 9
48
+ ```bash
49
+ npm install -D svelteesp32
50
+ ```
62
51
 
63
- ### Development
52
+ After building your frontend (Vite/Rollup/Webpack):
64
53
 
65
- #### Testing
54
+ ```bash
55
+ npx svelteesp32 -e psychic -s ./dist -o ./esp32/svelteesp32.h --etag=true
56
+ ```
66
57
 
67
- The project includes comprehensive unit tests using Vitest:
58
+ Include in your ESP32 project:
68
59
 
69
- ```bash
70
- # Run tests once
71
- npm run test
60
+ ```c
61
+ #include <PsychicHttp.h>
62
+ #include "svelteesp32.h"
72
63
 
73
- # Run tests in watch mode (for development)
74
- npm run test:watch
64
+ PsychicHttpServer server;
75
65
 
76
- # Generate coverage report
77
- npm run test:coverage
66
+ void setup() {
67
+ server.listen(80);
68
+ initSvelteStaticFiles(&server);
69
+ }
78
70
  ```
79
71
 
80
- **Test Coverage:** ~68% overall with focus on core functionality:
72
+ **That's it.** Your entire web app is now embedded and ready to serve.
81
73
 
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
74
+ ---
86
75
 
87
- Coverage reports are generated in the `coverage/` directory and can be viewed by opening `coverage/index.html` in a browser.
76
+ ## What's New
88
77
 
89
- #### Code Quality
78
+ - **v1.15.0** — `--basepath` 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
90
84
 
91
- ```bash
92
- # Check formatting
93
- npm run format:check
85
+ ---
94
86
 
95
- # Fix formatting
96
- npm run format:fix
87
+ ## Requirements
97
88
 
98
- # Check linting
99
- npm run lint:check
89
+ - Node.js >= 20
90
+ - npm >= 9
100
91
 
101
- # Fix linting issues
102
- npm run lint:fix
92
+ ---
103
93
 
104
- # Fix all formatting and linting issues
105
- npm run fix
106
- ```
94
+ ## Installation & Usage
107
95
 
108
- ### Usage
109
-
110
- **Install package** as dev dependency (it is practical if the package is part of the project so that you always receive updates)
96
+ ### Install
111
97
 
112
98
  ```bash
113
99
  npm install -D svelteesp32
114
100
  ```
115
101
 
116
- After a successful Svelte build (rollup/webpack/vite) **create an includable c++ header** file
102
+ ### Generate Header File
103
+
104
+ Choose your web server engine:
117
105
 
118
106
  ```bash
119
- // for PsychicHttpServer
120
- npx svelteesp32 -e psychic -s ../svelteapp/dist -o ../esp32project/svelteesp32.h --etag=true
107
+ # PsychicHttpServer (recommended for ESP32)
108
+ npx svelteesp32 -e psychic -s ./dist -o ./esp32/svelteesp32.h --etag=true
121
109
 
122
- // for PsychicHttpServer V2
123
- npx svelteesp32 -e psychic2 -s ../svelteapp/dist -o ../esp32project/svelteesp32.h --etag=true
110
+ # PsychicHttpServer V2
111
+ npx svelteesp32 -e psychic2 -s ./dist -o ./esp32/svelteesp32.h --etag=true
124
112
 
125
- // for ESPAsyncWebServer
126
- npx svelteesp32 -e async -s ../svelteapp/dist -o ../esp32project/svelteesp32.h --etag=true
113
+ # ESPAsyncWebServer (ESP32 + ESP8266)
114
+ npx svelteesp32 -e async -s ./dist -o ./esp32/svelteesp32.h --etag=true
127
115
 
128
- // for native esp-idf
129
- npx svelteesp32 -e espidf -s ../svelteapp/dist -o ../esp32project/svelteesp32.h --etag=true
116
+ # Native ESP-IDF
117
+ npx svelteesp32 -e espidf -s ./dist -o ./esp32/svelteesp32.h --etag=true
130
118
  ```
131
119
 
132
- During the **translation process**, the processed file details are visible with compression ratios, and at the end, the result shows the ESP's memory allocation (gzip size)
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
- The tool automatically:
135
+ **Automatic optimizations:**
146
136
 
147
- - Compresses files with gzip level 9 when beneficial (>1024 bytes and >15% reduction)
148
- - Detects and reports duplicate files using SHA256 hashing
149
- - Skips pre-compressed files (.gz, .br, .brottli) if the original exists
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
- **Include svelteesp32.h** into your Arduino or PlatformIO c++ project (copy it next to the main c++ file)
141
+ ### ESP32 Integration
152
142
 
153
- ```c
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
- or
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
- or for ESP-IDF native:
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
- You can find minimal buildable example projects in [demo/esp32](demo/esp32) (Arduino/PlatformIO) and [demo/esp32idf](demo/esp32idf) (ESP-IDF native) folders.
186
+ Working examples: [Arduino/PlatformIO](demo/esp32) | [ESP-IDF](demo/esp32idf)
187
+
188
+ ### What Gets Generated
219
189
 
220
- The content of **generated file** (do not edit, just use):
190
+ The generated header file includes everything your ESP needs:
221
191
 
222
192
  ```c
223
193
  //engine: PsychicHttpServer
@@ -257,12 +227,16 @@ const SVELTEESP32_FileInfo SVELTEESP32_FILES[] = {
257
227
  const size_t SVELTEESP32_FILE_COUNT = sizeof(SVELTEESP32_FILES) / sizeof(SVELTEESP32_FILES[0]);
258
228
  ...
259
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
+
260
233
  void initSvelteStaticFiles(PsychicHttpServer * server) {
261
234
  server->on("/assets/index-KwubEIf-.js", HTTP_GET, [](PsychicRequest * request) {
262
235
  if (request->hasHeader("If-None-Match") &&
263
236
  request->header("If-None-Match").equals(etag_assets_index_KwubEIf__js)) {
264
237
  PsychicResponse response304(request);
265
238
  response304.setCode(304);
239
+ SVELTEESP32_onFileServed("/assets/index-KwubEIf-.js", 304);
266
240
  return response304.send();
267
241
  }
268
242
 
@@ -272,23 +246,7 @@ void initSvelteStaticFiles(PsychicHttpServer * server) {
272
246
  response.addHeader("Cache-Control", "no-cache");
273
247
  response.addHeader("ETag", etag_assets_index_KwubEIf__js);
274
248
  response.setContent(datagzip_assets_index_KwubEIf__js, 12547);
275
- return response.send();
276
- });
277
-
278
- server->on("/assets/index-Soe6cpLA.css", HTTP_GET, [](PsychicRequest * request) {
279
- if (request->hasHeader("If-None-Match") &&
280
- request->header("If-None-Match").equals(etag_assets_index_Soe6cpLA_css)) {
281
- PsychicResponse response304(request);
282
- response304.setCode(304);
283
- return response304.send();
284
- }
285
-
286
- PsychicResponse response(request);
287
- response.setContentType("text/css");
288
- response.addHeader("Content-Encoding", "gzip");
289
- response.addHeader("Cache-Control", "no-cache");
290
- response.addHeader("ETag", etag_assets_index_Soe6cpLA_css);
291
- response.setContent(datagzip_assets_index_Soe6cpLA_css, 5368);
249
+ SVELTEESP32_onFileServed("/assets/index-KwubEIf-.js", 200);
292
250
  return response.send();
293
251
  });
294
252
 
@@ -296,461 +254,249 @@ void initSvelteStaticFiles(PsychicHttpServer * server) {
296
254
  }
297
255
  ```
298
256
 
299
- ### Engines and ESP variants
257
+ ---
300
258
 
301
- Four web server engines are supported:
259
+ ## Supported Web Server Engines
302
260
 
303
- - **`-e psychic`** (default): PsychicHttpServer V1 - Fast ESP32-only server using ESP-IDF internally. Recommended for ESP32 projects.
304
- - **`-e psychic2`**: PsychicHttpServer V2 - Updated version with improved API
305
- - **`-e async`**: ESPAsyncWebServer (https://github.com/ESP32Async/ESPAsyncWebServer) - Popular async server supporting both ESP32 and ESP8266/ESP8285
306
- - **`-e espidf`**: Native ESP-IDF web server - For projects using ESP-IDF framework directly (not Arduino)
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 |
307
267
 
308
- If you **only work on ESP32**, we recommend using PsychicHttpServer (`-e psychic` or `-e psychic2`), which uses the native ESP-IDF web server internally for significantly faster and more stable operation.
268
+ **Recommendation:** For ESP32-only projects, use PsychicHttpServer for the fastest, most stable experience.
309
269
 
310
- **Note for PsychicHttpServer users:** The generated header includes a comment suggesting to configure `server.config.max_uri_handlers` to match or exceed your file count to ensure all routes are properly registered.
270
+ **Note:** For PsychicHttp, configure `server.config.max_uri_handlers` to match your file count.
311
271
 
312
- ### Gzip
272
+ ---
313
273
 
314
- All modern browsers have been able to handle gzip-compressed content for years. For this reason, there is no question that the easily compressed JS and CSS files are stored compressed in the ESP32/ESP8266 and sent to the browser.
274
+ ## Features
315
275
 
316
- During the translation process, data in gzip format is generated and will be used if the **size is greater than 1024 bytes** and we experience a **reduction of at least 15%**. In such a case, the compressed data is unconditionally sent to the browser with the appropriate **Content-Encoding** header information.
276
+ ### Automatic Gzip Compression
317
277
 
318
- Automatic compression can be turned off with the `--gzip=false` option.
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.
319
279
 
320
- > This setting has three states: yes, no, and compiler mode is available. In compiler mode, you can disable/enable Gzip by setting the `SVELTEESP32_ENABLE_GZIP` c++ compiler directive. For example, if using platformio, just write `-D SVELTEESP32_ENABLE_GZIP`.
280
+ - **Enabled by default** disable with `--gzip=false`
281
+ - **Compiler mode** — use `--gzip=compiler` and control via `-D SVELTEESP32_ENABLE_GZIP` in PlatformIO
321
282
 
322
- ### ETag
283
+ ### Smart ETag Caching
323
284
 
324
- The ETag HTTP header can be used to significantly reduce network traffic. If the server sends ETag information, the client can check the integrity of the file by sending back this ETag (in `If-None-Match` header) without sending the data back again. All browsers use this function, the 304 HTTP response code is clearly visible in the network traffic.
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.
325
286
 
326
- Since microcontroller data traffic is moderately expensive, it is an individual decision whether to use the ETag or not. We **recommend using ETag**, which adds a bit more code (about 1-3%) but results in a much cleaner operation.
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`
327
290
 
328
- The use of ETag is **not enabled by default**, this can be achieved with the `--etag=true` switch.
291
+ All four engines support full ETag validation.
329
292
 
330
- All four engines (psychic, psychic2, async, espidf) fully support ETag validation with HTTP 304 Not Modified responses, reducing bandwidth usage when clients have valid cached content.
293
+ ### Browser Cache Control
331
294
 
332
- > This setting has three states: yes, no, and compiler mode is available. In compiler mode, you can disable/enable ETag by setting the `SVELTEESP32_ENABLE_ETAG` c++ compiler directive. For example, if using platformio, just type `-D SVELTEESP32_ENABLE_ETAG`.
295
+ Fine-tune how browsers cache your content:
333
296
 
334
- ### Cache-control
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
335
299
 
336
- By default (when using the ETag), we send no-cache in the cache-control header of the HTTP response. Pages, subpages and other elements are downloaded every time. This is perfectly acceptable when serving small pages with ESP.
300
+ ### Automatic Index Handling
337
301
 
338
- At the same time, it can be an advantage that the content is cached by the browser and not even the ETag check is performed. For this, you can specify how many seconds the max-age value sent instead of no-cache should be. In the case of `--cachetime=86400` (max-age=86400), the page (and other elements) will not be downloaded by the browser **for one day**.
302
+ Your `index.html` is automatically served at the root URL just like any web server. Visit `http://esp32.local/` and your app loads.
339
303
 
340
- ### Main entry point - index.html
341
-
342
- Typically, the entry point for web applications is the **index.htm or index.html** file. This does not need to be listed in the browser's address bar because web servers know that this file should be served by default. Svelteesp32 also does this: if there is an index.htm or index.html file, it sets it as the main file to be served. So using `http://esp_xxx.local` or just entering the `http://x.y.w.z/` IP address will serve this main file.
343
-
344
- **Validation**: By default, svelteesp32 validates that an `index.html` or `index.htm` file exists in your source directory (in the root or any subdirectory). This ensures users won't get a 404 error when visiting your ESP32's root URL.
345
-
346
- **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 `--noindexcheck`:
347
305
 
348
306
  ```bash
349
- # API-only application (no web UI)
350
- npx svelteesp32 -e psychic -s ./dist -o ./output.h --no-index-check
351
-
352
- # Custom entry point (users must visit /main.html explicitly)
353
- npx svelteesp32 -e psychic -s ./dist -o ./output.h --no-index-check
307
+ npx svelteesp32 -e psychic -s ./dist -o ./output.h --noindexcheck
354
308
  ```
355
309
 
356
310
  ### File Exclusion
357
311
 
358
- The `--exclude` option allows you to exclude files from being embedded in the ESP32 firmware using glob patterns. This is useful for excluding source maps, documentation, and test files that shouldn't be part of the deployed application.
359
-
360
- #### Basic Usage
312
+ Keep source maps, docs, and test files out of your firmware:
361
313
 
362
314
  ```bash
363
- # Exclude source maps
364
- npx svelteesp32 -e psychic -s ./dist -o ./output.h --exclude="*.map"
365
-
366
- # Exclude documentation files
367
- npx svelteesp32 -e psychic -s ./dist -o ./output.h --exclude="*.md"
315
+ # Single pattern
316
+ npx svelteesp32 -s ./dist -o ./output.h --exclude="*.map"
368
317
 
369
- # Exclude multiple file types (comma-separated)
370
- npx svelteesp32 -e psychic -s ./dist -o ./output.h --exclude="*.map,*.md,*.txt"
371
-
372
- # Exclude using multiple flags
373
- npx svelteesp32 -e psychic -s ./dist -o ./output.h --exclude="*.map" --exclude="*.md"
374
-
375
- # Exclude entire directories
376
- npx svelteesp32 -e psychic -s ./dist -o ./output.h --exclude="test/**/*"
377
-
378
- # Combine multiple approaches
379
- 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/**/*"
380
320
  ```
381
321
 
382
- #### Pattern Syntax
383
-
384
- The exclude patterns use standard glob syntax:
385
-
386
- - `*.map` - Match all files ending with `.map`
387
- - `**/*.test.js` - Match all `.test.js` files in any directory
388
- - `test/**/*` - Match all files in the `test` directory and subdirectories
389
- - `.DS_Store` - Match specific filename
390
-
391
- #### Default Exclusions
392
-
393
- By default, the following system and development files are automatically excluded:
322
+ **Default exclusions:** `.DS_Store`, `Thumbs.db`, `.git`, `.svn`, `*.swp`, `*~`, `.gitignore`, `.gitattributes`
394
323
 
395
- - `.DS_Store` (macOS system file)
396
- - `Thumbs.db` (Windows thumbnail cache)
397
- - `.git` (Git directory)
398
- - `.svn` (SVN directory)
399
- - `*.swp` (Vim swap files)
400
- - `*~` (Backup files)
401
- - `.gitignore` (Git ignore file)
402
- - `.gitattributes` (Git attributes file)
403
-
404
- Custom exclude patterns are added to these defaults.
405
-
406
- #### Exclusion Output
407
-
408
- When files are excluded, you'll see a summary in the build output:
324
+ Build output shows exactly what's excluded:
409
325
 
410
326
  ```
411
- Excluded 5 file(s):
327
+ Excluded 3 file(s):
412
328
  - assets/index.js.map
413
329
  - assets/vendor.js.map
414
330
  - README.md
415
- - docs/guide.md
416
- - test/unit.test.js
417
331
  ```
418
332
 
419
- This helps you verify that the correct files are being excluded from your build.
333
+ ### Multiple Frontends (Base Path)
420
334
 
421
- ### C++ defines
335
+ Serve multiple web apps from one ESP32 using URL prefixes:
422
336
 
423
- To make it easy to integrate into a larger c++ project, we have made a couple of variables available as c++ defines.
424
-
425
- You can use the COUNT and SIZE constants:
337
+ ```bash
338
+ npx svelteesp32 -s ./admin-dist -o ./admin.h --basepath=/admin
339
+ npx svelteesp32 -s ./user-dist -o ./user.h --basepath=/app
340
+ ```
426
341
 
427
342
  ```c
428
- ...
429
- #include "svelteesp32.h"
343
+ #include "admin.h" // Serves at /admin/*
344
+ #include "user.h" // Serves at /app/*
430
345
 
431
- #if SVELTEESP32_COUNT != 5
432
- #error Invalid file count
433
- #endif
434
- ...
346
+ void setup() {
347
+ server.listen(80);
348
+ initSvelteStaticFiles_admin(&server);
349
+ initSvelteStaticFiles_user(&server);
350
+ server.on("/api/data", HTTP_GET, handleApiData);
351
+ }
435
352
  ```
436
353
 
437
- You can include a blocker error if a named file accidentally missing from the build:
438
-
439
- ```c
440
- ...
441
- #include "svelteesp32.h"
354
+ **Rules:** Must start with `/`, no trailing slash, no double slashes.
442
355
 
443
- #ifndef SVELTEESP32_FILE_INDEX_HTML
444
- #error Missing index file
445
- #endif
446
- ...
447
- ```
356
+ ### C++ Build-Time Validation
448
357
 
449
- ...or if there are too many of a file type:
358
+ Catch configuration issues at compile time with generated defines:
450
359
 
451
360
  ```c
452
- ...
453
361
  #include "svelteesp32.h"
454
362
 
455
- #if SVELTEESP32_CSS_FILES > 1
456
- #error Too many CSS files
363
+ #if SVELTEESP32_COUNT != 5
364
+ #error Unexpected file count - check your build
457
365
  #endif
458
- ...
459
- ```
460
366
 
461
- 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!)
367
+ #ifndef SVELTEESP32_FILE_INDEX_HTML
368
+ #error Missing index.html - frontend build failed?
369
+ #endif
370
+ ```
462
371
 
463
- ### File Manifest
372
+ **Available defines:** `SVELTEESP32_COUNT`, `SVELTEESP32_SIZE`, `SVELTEESP32_SIZE_GZIP`, `SVELTEESP32_FILE_*`, `SVELTEESP32_*_FILES`
464
373
 
465
- The generated header includes a file manifest struct and array that allows runtime introspection of all embedded static assets. This is useful for logging, runtime diagnostics, or building a JSON endpoint that lists all served files.
374
+ ### Runtime File Manifest
466
375
 
467
- **Generated Structure:**
376
+ Query embedded files at runtime for logging, diagnostics, or API endpoints:
468
377
 
469
378
  ```c
470
- // File manifest struct
471
- struct SVELTEESP32_FileInfo {
472
- const char* path; // URL path (e.g., "/index.html")
473
- uint32_t size; // Original file size in bytes
474
- uint32_t gzipSize; // Compressed size (0 if not gzipped)
475
- const char* etag; // ETag pointer (nullptr if etag disabled)
476
- const char* contentType; // MIME type (e.g., "text/html")
477
- };
478
-
479
- // File manifest array
480
- const SVELTEESP32_FileInfo SVELTEESP32_FILES[] = { ... };
481
- const size_t SVELTEESP32_FILE_COUNT = sizeof(SVELTEESP32_FILES) / sizeof(SVELTEESP32_FILES[0]);
482
- ```
483
-
484
- **Usage Example - List All Files:**
485
-
486
- ```c
487
- #include "svelteesp32.h"
488
-
489
- void listFiles() {
490
- Serial.printf("Embedded files (%d):\n", SVELTEESP32_FILE_COUNT);
491
- for (size_t i = 0; i < SVELTEESP32_FILE_COUNT; i++) {
379
+ // List all embedded files
380
+ for (size_t i = 0; i < SVELTEESP32_FILE_COUNT; i++) {
492
381
  const auto& f = SVELTEESP32_FILES[i];
493
- Serial.printf(" %s (%d bytes", f.path, f.size);
494
- if (f.gzipSize > 0) {
495
- Serial.printf(", gzip: %d bytes", f.gzipSize);
496
- }
497
- Serial.printf(", type: %s)\n", f.contentType);
498
- }
382
+ Serial.printf("%s (%d bytes, gzip: %d)\n", f.path, f.size, f.gzipSize);
499
383
  }
500
384
  ```
501
385
 
502
- **Usage Example - JSON Endpoint:**
386
+ Each file entry includes: `path`, `size`, `gzipSize`, `etag`, `contentType`
387
+
388
+ ### Request Hook (Metrics & Logging)
389
+
390
+ Track every request with zero overhead when unused (weak linkage):
503
391
 
504
392
  ```c
505
- server->on("/api/files", HTTP_GET, [](PsychicRequest* request) {
506
- String json = "[";
507
- for (size_t i = 0; i < SVELTEESP32_FILE_COUNT; i++) {
508
- const auto& f = SVELTEESP32_FILES[i];
509
- if (i > 0) json += ",";
510
- json += "{\"path\":\"" + String(f.path) + "\",";
511
- json += "\"size\":" + String(f.size) + ",";
512
- json += "\"gzipSize\":" + String(f.gzipSize) + ",";
513
- json += "\"contentType\":\"" + String(f.contentType) + "\"}";
514
- }
515
- json += "]";
516
- PsychicResponse response(request);
517
- response.setContentType("application/json");
518
- response.setContent(json.c_str(), json.length());
519
- return response.send();
520
- });
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
+ }
521
397
  ```
522
398
 
523
- **Notes:**
399
+ Called for every response (200 = content served, 304 = cache hit).
524
400
 
525
- - The manifest is always generated (no CLI flag needed)
526
- - `gzipSize` is 0 when the file is not gzipped (either too small, poor compression ratio, or gzip disabled)
527
- - `etag` is `NULL` when etag is disabled (`--etag=false`)
528
- - The struct and array names use the `--define` prefix (default: `SVELTEESP32`)
529
- - For ESP-IDF engine, C-compatible `typedef struct` syntax is used instead of C++ `struct`
401
+ ---
530
402
 
531
- ### Command line options
403
+ ## CLI Reference
532
404
 
533
- | Option | Description | default |
534
- | ------------------ | ------------------------------------------------------------------------------------ | ----------------------- |
535
- | `-s` | **Source dist folder contains compiled web files** | (required) |
536
- | `-e` | The engine for which the include file is created (psychic/psychic2/async/espidf) | psychic |
537
- | `-o` | Generated output file with path | `svelteesp32.h` |
538
- | `--exclude` | Exclude files matching glob pattern (repeatable or comma-separated) | Default system files |
539
- | `--etag` | Use ETag header for cache (true/false/compiler) | false |
540
- | `--cachetime` | Override no-cache response with a max-age=\<cachetime\> response (seconds) | 0 |
541
- | `--gzip` | Compress content with gzip (true/false/compiler) | true |
542
- | `--created` | Include creation time in generated header | false |
543
- | `--version` | Include a version string in generated header, e.g. `--version=v$npm_package_version` | '' |
544
- | `--espmethod` | Name of generated initialization method | `initSvelteStaticFiles` |
545
- | `--define` | Prefix of c++ defines (e.g., SVELTEESP32_COUNT) | `SVELTEESP32` |
546
- | `--config` | Use custom RC file path | `.svelteesp32rc.json` |
547
- | `--no-index-check` | Skip validation for index.html/index.htm (for API-only or custom entry points) | false |
548
- | `-h` | Show help | |
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
+ | `--basepath` | 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
+ | `--noindexcheck` | Skip index.html validation | `false` |
420
+ | `-h` | Show help | |
549
421
 
550
- ### Configuration File
422
+ ---
551
423
 
552
- 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.
424
+ ## Configuration File
553
425
 
554
- #### Quick Start
555
-
556
- Create `.svelteesp32rc.json` in your project directory:
426
+ Store your settings in `.svelteesp32rc.json` for zero-argument builds:
557
427
 
558
428
  ```json
559
429
  {
560
430
  "engine": "psychic",
561
431
  "sourcepath": "./dist",
562
- "outputfile": "./esp32/include/svelteesp32.h",
432
+ "outputfile": "./esp32/svelteesp32.h",
563
433
  "etag": "true",
564
434
  "gzip": "true",
565
- "cachetime": 86400,
566
435
  "exclude": ["*.map", "*.md"]
567
436
  }
568
437
  ```
569
438
 
570
- Then simply run:
439
+ Then just run:
571
440
 
572
441
  ```bash
573
442
  npx svelteesp32
574
443
  ```
575
444
 
576
- No command line arguments needed!
577
-
578
- #### Search Locations
579
-
580
- The tool automatically searches for `.svelteesp32rc.json` in:
581
-
582
- 1. Current working directory
583
- 2. User home directory
584
-
585
- Or specify a custom location:
586
-
587
- ```bash
588
- npx svelteesp32 --config=.svelteesp32rc.prod.json
589
- ```
590
-
591
- #### Configuration Reference
592
-
593
- All CLI options can be specified in the RC file using long-form property names:
594
-
595
- | RC Property | CLI Flag | Type | Example |
596
- | -------------- | ------------------ | ------- | ------------------------------------------------ |
597
- | `engine` | `-e` | string | `"psychic"`, `"psychic2"`, `"async"`, `"espidf"` |
598
- | `sourcepath` | `-s` | string | `"./dist"` |
599
- | `outputfile` | `-o` | string | `"./output.h"` |
600
- | `etag` | `--etag` | string | `"true"`, `"false"`, `"compiler"` |
601
- | `gzip` | `--gzip` | string | `"true"`, `"false"`, `"compiler"` |
602
- | `cachetime` | `--cachetime` | number | `86400` |
603
- | `created` | `--created` | boolean | `true`, `false` |
604
- | `version` | `--version` | string | `"v1.0.0"` |
605
- | `espmethod` | `--espmethod` | string | `"initSvelteStaticFiles"` |
606
- | `define` | `--define` | string | `"SVELTEESP32"` |
607
- | `exclude` | `--exclude` | array | `["*.map", "*.md"]` |
608
- | `noIndexCheck` | `--no-index-check` | boolean | `true`, `false` |
609
-
610
- #### CLI Override
611
-
612
- Command line arguments always take precedence over RC file values:
613
-
614
- ```bash
615
- # Use RC settings but override etag
616
- npx svelteesp32 --etag=false
617
-
618
- # Use RC settings but add different exclude pattern
619
- npx svelteesp32 --exclude="*.txt"
620
- ```
621
-
622
- #### Multiple Environments
623
-
624
- Create different config files for different environments:
625
-
626
- ```bash
627
- # Development build
628
- npx svelteesp32 --config=.svelteesp32rc.dev.json
629
-
630
- # Production build
631
- npx svelteesp32 --config=.svelteesp32rc.prod.json
632
- ```
633
-
634
- #### Exclude Pattern Behavior
635
-
636
- **Replace mode**: When you specify `exclude` patterns in RC file or CLI, they completely replace the defaults.
445
+ ### npm Variable Interpolation
637
446
 
638
- - **No exclude specified**: Uses default system exclusions (`.DS_Store`, `Thumbs.db`, `.git`, etc.)
639
- - **RC file has exclude**: Replaces defaults with RC patterns
640
- - **CLI has --exclude**: Replaces RC patterns (or defaults if no RC)
641
-
642
- Example:
643
-
644
- ```json
645
- // .svelteesp32rc.json
646
- { "exclude": ["*.map"] }
647
- ```
648
-
649
- Result: Only `*.map` is excluded (default patterns are replaced)
650
-
651
- To keep defaults, explicitly list them in your RC file:
447
+ Sync versions and names automatically from your `package.json`:
652
448
 
653
449
  ```json
654
450
  {
655
- "exclude": [".DS_Store", "Thumbs.db", ".git", "*.map", "*.md"]
656
- }
657
- ```
658
-
659
- #### NPM Package Variable Interpolation
660
-
661
- RC files support automatic variable interpolation from your `package.json`. This allows you to reference package.json fields in your RC configuration using npm-style variable syntax.
662
-
663
- **Syntax:** `$npm_package_<field_name>`
664
-
665
- **Supported in:** All string fields (`version`, `define`, `sourcepath`, `outputfile`, `espmethod`, `exclude` patterns)
666
-
667
- **Example:**
668
-
669
- ```json
670
- // .svelteesp32rc.json
671
- {
672
- "engine": "psychic",
673
451
  "version": "v$npm_package_version",
674
- "define": "$npm_package_name",
675
- "sourcepath": "./dist",
676
- "outputfile": "./output.h"
677
- }
678
- ```
679
-
680
- With `package.json` containing:
681
-
682
- ```json
683
- {
684
- "name": "my-esp32-app",
685
- "version": "2.1.0"
686
- }
687
- ```
688
-
689
- The variables are automatically interpolated to:
690
-
691
- ```json
692
- {
693
- "version": "v2.1.0",
694
- "define": "my_esp32_app"
452
+ "define": "$npm_package_name"
695
453
  }
696
454
  ```
697
455
 
698
- **Nested Fields:**
456
+ With `package.json` containing `"version": "2.1.0"`, this becomes `"version": "v2.1.0"`.
699
457
 
700
- You can access nested package.json fields using underscores:
458
+ ### Multiple Environments
701
459
 
702
- ```json
703
- // package.json
704
- {
705
- "name": "myapp",
706
- "repository": {
707
- "type": "git",
708
- "url": "https://github.com/user/repo.git"
709
- }
710
- }
711
-
712
- // .svelteesp32rc.json
713
- {
714
- "version": "$npm_package_repository_type"
715
- }
716
- // Results in: "version": "git"
460
+ ```bash
461
+ npx svelteesp32 --config=.svelteesp32rc.prod.json
717
462
  ```
718
463
 
719
- **Multiple Variables:**
720
-
721
- Combine multiple variables in a single field:
464
+ CLI arguments always override RC file values.
722
465
 
723
- ```json
724
- {
725
- "version": "$npm_package_name-v$npm_package_version-release"
726
- }
727
- // Results in: "my-esp32-app-v2.1.0-release"
728
- ```
466
+ ---
729
467
 
730
- **Requirements:**
468
+ ## FAQ
731
469
 
732
- - `package.json` must exist in the same directory as the RC file
733
- - If variables are used but `package.json` is not found, an error is thrown with details about which fields contain variables
734
- - 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.
735
472
 
736
- **Use Cases:**
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.
737
475
 
738
- - **Version Synchronization:** Keep header version in sync with npm package version
739
- - **Dynamic Naming:** Use package name for C++ defines automatically
740
- - **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.
741
478
 
742
- ### Q&A
479
+ **Does compilation take forever?**
480
+ No. Large headers compile in seconds, and incremental builds skip recompilation if your frontend hasn't changed.
743
481
 
744
- - **How big a frontend application can be placed?** If you compress the content with gzip, even a 3-4Mb assets directory can be placed. This is a serious enough amount to serve a complete application.
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.
745
484
 
746
- - **How fast is cpp file compilation?** The cpp (.h) file can be large, but it can be compiled in a few seconds on any machine. If you don't modify your svelte/react app, it will use the already compiled cpp file (not recompile). This does not increase the speed of ESP32/ESP8266 development.
485
+ ---
747
486
 
748
- - **Does the solution use PROGMEM?** It depends on the engine. For PsychicHttpServer (`psychic`, `psychic2`) and ESP-IDF (`espidf`) engines, const arrays are used which are automatically placed in program memory on ESP32. For ESPAsyncWebServer (`async`), PROGMEM directive is explicitly used to support ESP8266/ESP8285. In both cases, the file data is stored in flash memory, not RAM, so your heap and stack remain available for your application.
487
+ ## Development
749
488
 
750
- - **Why is the .h file so big?** The source files are always larger than the binary compiled from them. The .h file contains byte arrays in text format (comma-separated decimal numbers), which takes more space than the binary data itself. The actual memory allocation is shown in the header file defines (SVELTEESP32_SIZE for uncompressed, SVELTEESP32_SIZE_GZIP for compressed).
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
+ ```
751
495
 
752
- - **Is collaboration between groups supported?** Yes, the Frontend team produces the application, the use of svelteesp32 is part of the build process. Then, provided with a version number, the .h file is placed in git, which the ESP team translates into the platformio application.
496
+ ---
753
497
 
754
- - **Will you develop it further?** Since I use it myself, I will do my best to make the solution better and better.
498
+ **Ready to ship your web UI in a single binary?**
755
499
 
756
- - **Is this safe to use in production?** I suggest you give it a try! If you find it useful and safe in several different situations, feel free to use it, just like any other free library.
500
+ ```bash
501
+ npm install -D svelteesp32
502
+ ```