svelteesp32 1.9.1 → 1.9.3
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 +102 -41
- package/dist/cppCode.js +159 -232
- package/dist/cppCodeEspIdf.d.ts +1 -1
- package/dist/cppCodeEspIdf.js +36 -0
- package/dist/file.js +32 -21
- package/dist/index.js +37 -32
- package/package.json +14 -11
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@ This npm package provides a solution for **inserting any JS client application i
|
|
|
18
18
|
|
|
19
19
|
> Starting with version v1.7.0, with the cachetime command line option, you can set whether the browser can cache pages
|
|
20
20
|
|
|
21
|
-
> Starting with version v1.6.0, mime
|
|
21
|
+
> Starting with version v1.6.0, mime-types package properly handles MIME types (application/javascript -> text/javascript)
|
|
22
22
|
|
|
23
23
|
> Starting with version v1.5.0, PsychicHttp v2 is also supported.
|
|
24
24
|
|
|
@@ -30,6 +30,11 @@ This npm package provides a solution for **inserting any JS client application i
|
|
|
30
30
|
|
|
31
31
|
> Starting with version v1.1.0, the ETag header is also supported.
|
|
32
32
|
|
|
33
|
+
### Requirements
|
|
34
|
+
|
|
35
|
+
- Node.js >= 20
|
|
36
|
+
- npm >= 9
|
|
37
|
+
|
|
33
38
|
### Usage
|
|
34
39
|
|
|
35
40
|
**Install package** as devDependency (it is practical if the package is part of the project so that you always receive updates)
|
|
@@ -54,19 +59,25 @@ npx svelteesp32 -e async -s ../svelteapp/dist -o ../esp32project/svelteesp32.h -
|
|
|
54
59
|
npx svelteesp32 -e espidf -s ../svelteapp/dist -o ../esp32project/svelteesp32.h --etag=true
|
|
55
60
|
```
|
|
56
61
|
|
|
57
|
-
During the **translation process**, the processed file details are visible, and at the end, the result shows the ESP's memory allocation (gzip size)
|
|
62
|
+
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)
|
|
58
63
|
|
|
59
64
|
```
|
|
60
|
-
[assets/index-KwubEIf-.js] ✓ gzip used (38850 -> 12547)
|
|
61
|
-
[assets/index-Soe6cpLA.css] ✓ gzip used (32494 -> 5368)
|
|
62
|
-
[favicon.png] x gzip unused (33249 -> 33282)
|
|
63
|
-
[index.html] x gzip unused (too small) (472 -> 308)
|
|
64
|
-
[roboto_regular.json] ✓ gzip used (363757 -> 93567)
|
|
65
|
+
[assets/index-KwubEIf-.js] ✓ gzip used (38850 -> 12547 = 32%)
|
|
66
|
+
[assets/index-Soe6cpLA.css] ✓ gzip used (32494 -> 5368 = 17%)
|
|
67
|
+
[favicon.png] x gzip unused (33249 -> 33282 = 100%)
|
|
68
|
+
[index.html] x gzip unused (too small) (472 -> 308 = 65%)
|
|
69
|
+
[roboto_regular.json] ✓ gzip used (363757 -> 93567 = 26%)
|
|
65
70
|
|
|
66
71
|
5 files, 458kB original size, 142kB gzip size
|
|
67
72
|
../../../Arduino/EspSvelte/svelteesp32.h 842kB size
|
|
68
73
|
```
|
|
69
74
|
|
|
75
|
+
The tool automatically:
|
|
76
|
+
|
|
77
|
+
- Compresses files with gzip level 9 when beneficial (>1024 bytes and >15% reduction)
|
|
78
|
+
- Detects and reports duplicate files using SHA256 hashing
|
|
79
|
+
- Skips pre-compressed files (.gz, .br, .brottli) if the original exists
|
|
80
|
+
|
|
70
81
|
**Include svelteesp32.h** into your Arduino or PlatformIO c++ project (copy it next to the main c++ file)
|
|
71
82
|
|
|
72
83
|
```c
|
|
@@ -111,59 +122,107 @@ void setup()
|
|
|
111
122
|
}
|
|
112
123
|
```
|
|
113
124
|
|
|
114
|
-
|
|
125
|
+
or for ESP-IDF native:
|
|
126
|
+
|
|
127
|
+
```c
|
|
128
|
+
...
|
|
129
|
+
|
|
130
|
+
#include <esp_http_server.h>
|
|
131
|
+
#include "svelteesp32.h"
|
|
132
|
+
|
|
133
|
+
httpd_handle_t server = NULL;
|
|
134
|
+
|
|
135
|
+
...
|
|
136
|
+
|
|
137
|
+
void app_main()
|
|
138
|
+
{
|
|
139
|
+
...
|
|
140
|
+
|
|
141
|
+
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
|
|
142
|
+
httpd_start(&server, &config);
|
|
143
|
+
|
|
144
|
+
initSvelteStaticFiles(server);
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
You can find minimal buildable example projects in [demo/esp32](demo/esp32) (Arduino/PlatformIO) and [demo/esp32idf](demo/esp32idf) (ESP-IDF native) folders.
|
|
115
149
|
|
|
116
|
-
The content of **generated file** (do not edit, just use)
|
|
150
|
+
The content of **generated file** (do not edit, just use):
|
|
117
151
|
|
|
118
152
|
```c
|
|
153
|
+
//engine: PsychicHttpServer
|
|
154
|
+
//cmdline: -e psychic -s ./dist -o ./output.h --etag=true --gzip=true
|
|
155
|
+
//
|
|
119
156
|
#define SVELTEESP32_COUNT 5
|
|
120
|
-
#define SVELTEESP32_SIZE
|
|
157
|
+
#define SVELTEESP32_SIZE 468822
|
|
158
|
+
#define SVELTEESP32_SIZE_GZIP 145633
|
|
121
159
|
#define SVELTEESP32_FILE_INDEX_HTML
|
|
122
160
|
#define SVELTEESP32_HTML_FILES 1
|
|
161
|
+
#define SVELTEESP32_CSS_FILES 1
|
|
162
|
+
#define SVELTEESP32_JS_FILES 1
|
|
123
163
|
...
|
|
124
164
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
165
|
+
#include <Arduino.h>
|
|
166
|
+
#include <PsychicHttp.h>
|
|
167
|
+
#include <PsychicHttpsServer.h>
|
|
168
|
+
|
|
169
|
+
const uint8_t datagzip_assets_index_KwubEIf__js[12547] = {0x1f, 0x8b, 0x8, 0x0, ...
|
|
170
|
+
const uint8_t datagzip_assets_index_Soe6cpLA_css[5368] = {0x1f, 0x8b, 0x8, 0x0, 0x0, ...
|
|
171
|
+
const char * etag_assets_index_KwubEIf__js = "387b88e345cc56ef9091...";
|
|
172
|
+
const char * etag_assets_index_Soe6cpLA_css = "d4f23bc45ef67890ab12...";
|
|
173
|
+
...
|
|
128
174
|
|
|
129
175
|
void initSvelteStaticFiles(PsychicHttpServer * server) {
|
|
130
|
-
server->on("/assets/index-KwubEIf-.js", HTTP_GET, [](PsychicRequest * request)
|
|
131
|
-
|
|
132
|
-
|
|
176
|
+
server->on("/assets/index-KwubEIf-.js", HTTP_GET, [](PsychicRequest * request) {
|
|
177
|
+
if (request->hasHeader("If-None-Match") &&
|
|
178
|
+
request->header("If-None-Match").equals(etag_assets_index_KwubEIf__js)) {
|
|
133
179
|
PsychicResponse response304(request);
|
|
134
180
|
response304.setCode(304);
|
|
135
181
|
return response304.send();
|
|
136
182
|
}
|
|
137
183
|
|
|
138
184
|
PsychicResponse response(request);
|
|
139
|
-
response.setContentType("
|
|
185
|
+
response.setContentType("text/javascript");
|
|
140
186
|
response.addHeader("Content-Encoding", "gzip");
|
|
141
|
-
response.
|
|
187
|
+
response.addHeader("Cache-Control", "no-cache");
|
|
188
|
+
response.addHeader("ETag", etag_assets_index_KwubEIf__js);
|
|
189
|
+
response.setContent(datagzip_assets_index_KwubEIf__js, 12547);
|
|
142
190
|
return response.send();
|
|
143
191
|
});
|
|
144
192
|
|
|
145
|
-
server->on("/assets/index-Soe6cpLA.css", HTTP_GET, [](PsychicRequest * request)
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
193
|
+
server->on("/assets/index-Soe6cpLA.css", HTTP_GET, [](PsychicRequest * request) {
|
|
194
|
+
if (request->hasHeader("If-None-Match") &&
|
|
195
|
+
request->header("If-None-Match").equals(etag_assets_index_Soe6cpLA_css)) {
|
|
196
|
+
PsychicResponse response304(request);
|
|
197
|
+
response304.setCode(304);
|
|
198
|
+
return response304.send();
|
|
149
199
|
}
|
|
150
200
|
|
|
151
201
|
PsychicResponse response(request);
|
|
152
202
|
response.setContentType("text/css");
|
|
153
203
|
response.addHeader("Content-Encoding", "gzip");
|
|
154
|
-
response.
|
|
204
|
+
response.addHeader("Cache-Control", "no-cache");
|
|
205
|
+
response.addHeader("ETag", etag_assets_index_Soe6cpLA_css);
|
|
206
|
+
response.setContent(datagzip_assets_index_Soe6cpLA_css, 5368);
|
|
155
207
|
return response.send();
|
|
156
208
|
});
|
|
157
209
|
|
|
158
|
-
|
|
210
|
+
// ... more routes
|
|
159
211
|
}
|
|
160
212
|
```
|
|
161
213
|
|
|
162
214
|
### Engines and ESP variants
|
|
163
215
|
|
|
164
|
-
|
|
216
|
+
Four web server engines are supported:
|
|
165
217
|
|
|
166
|
-
|
|
218
|
+
- **`-e psychic`** (default): PsychicHttpServer V1 - Fast ESP32-only server using ESP-IDF internally. Recommended for ESP32 projects.
|
|
219
|
+
- **`-e psychic2`**: PsychicHttpServer V2 - Updated version with improved API
|
|
220
|
+
- **`-e async`**: ESPAsyncWebServer (https://github.com/ESP32Async/ESPAsyncWebServer) - Popular async server supporting both ESP32 and ESP8266/ESP8285
|
|
221
|
+
- **`-e espidf`**: Native ESP-IDF web server - For projects using ESP-IDF framework directly (not Arduino)
|
|
222
|
+
|
|
223
|
+
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.
|
|
224
|
+
|
|
225
|
+
**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.
|
|
167
226
|
|
|
168
227
|
### Gzip
|
|
169
228
|
|
|
@@ -183,6 +242,8 @@ Since microcontroller data traffic is moderately expensive, it is an individual
|
|
|
183
242
|
|
|
184
243
|
The use of ETag is **not enabled by default**, this can be achieved with the `--etag=true` switch.
|
|
185
244
|
|
|
245
|
+
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.
|
|
246
|
+
|
|
186
247
|
> 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`.
|
|
187
248
|
|
|
188
249
|
### Cache-control
|
|
@@ -239,19 +300,19 @@ You can use the following c++ directives at the project level if you want to con
|
|
|
239
300
|
|
|
240
301
|
### Command line options
|
|
241
302
|
|
|
242
|
-
| Option | Description
|
|
243
|
-
| ------------- |
|
|
244
|
-
| `-s` | **Source dist folder contains compiled web files**
|
|
245
|
-
| `-e` | The engine for which the include file is created (psychic/psychic2/async)
|
|
246
|
-
| `-o` | Generated output file with path
|
|
247
|
-
| `--etag` | Use ETag header for cache (true/false/compiler)
|
|
248
|
-
| `--cachetime` | Override no-cache response with a max-age
|
|
249
|
-
| `--gzip` | Compress content with gzip (true/false/compiler)
|
|
250
|
-
| `--created` | Include creation time
|
|
251
|
-
| `--version` | Include a version string, `--version=v$npm_package_version`
|
|
252
|
-
| `--espmethod` | Name of generated method
|
|
253
|
-
| `--define` | Prefix of c++ defines
|
|
254
|
-
| `-h` | Show help
|
|
303
|
+
| Option | Description | default |
|
|
304
|
+
| ------------- | ------------------------------------------------------------------------------------ | ----------------------- |
|
|
305
|
+
| `-s` | **Source dist folder contains compiled web files** | (required) |
|
|
306
|
+
| `-e` | The engine for which the include file is created (psychic/psychic2/async/espidf) | psychic |
|
|
307
|
+
| `-o` | Generated output file with path | `svelteesp32.h` |
|
|
308
|
+
| `--etag` | Use ETag header for cache (true/false/compiler) | false |
|
|
309
|
+
| `--cachetime` | Override no-cache response with a max-age=\<cachetime\> response (seconds) | 0 |
|
|
310
|
+
| `--gzip` | Compress content with gzip (true/false/compiler) | true |
|
|
311
|
+
| `--created` | Include creation time in generated header | false |
|
|
312
|
+
| `--version` | Include a version string in generated header, e.g. `--version=v$npm_package_version` | '' |
|
|
313
|
+
| `--espmethod` | Name of generated initialization method | `initSvelteStaticFiles` |
|
|
314
|
+
| `--define` | Prefix of c++ defines (e.g., SVELTEESP32_COUNT) | `SVELTEESP32` |
|
|
315
|
+
| `-h` | Show help | |
|
|
255
316
|
|
|
256
317
|
### Q&A
|
|
257
318
|
|
|
@@ -259,9 +320,9 @@ You can use the following c++ directives at the project level if you want to con
|
|
|
259
320
|
|
|
260
321
|
- **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.
|
|
261
322
|
|
|
262
|
-
- **Does the solution use PROGMEM?**
|
|
323
|
+
- **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.
|
|
263
324
|
|
|
264
|
-
- **Why is the .h file so big?** The source files are always larger than the binary compiled from them.
|
|
325
|
+
- **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).
|
|
265
326
|
|
|
266
327
|
- **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.
|
|
267
328
|
|
package/dist/cppCode.js
CHANGED
|
@@ -4,15 +4,7 @@ exports.getCppCode = void 0;
|
|
|
4
4
|
const handlebars_1 = require("handlebars");
|
|
5
5
|
const commandLine_1 = require("./commandLine");
|
|
6
6
|
const cppCodeEspIdf_1 = require("./cppCodeEspIdf");
|
|
7
|
-
const
|
|
8
|
-
//engine: PsychicHttpServer
|
|
9
|
-
//cmdline: {{{commandLine}}}
|
|
10
|
-
//You should use server.config.max_uri_handlers = {{fileCount}}; or higher value to proper handles all files
|
|
11
|
-
{{#if created }}
|
|
12
|
-
//created: {{now}}
|
|
13
|
-
{{/if}}
|
|
14
|
-
//
|
|
15
|
-
|
|
7
|
+
const commonHeaderSection = `
|
|
16
8
|
{{#switch etag}}
|
|
17
9
|
{{#case "true"}}
|
|
18
10
|
#ifdef {{definePrefix}}_ENABLE_ETAG
|
|
@@ -56,38 +48,36 @@ const psychicTemplate = `
|
|
|
56
48
|
{{#each filesByExtension}}
|
|
57
49
|
#define {{../definePrefix}}_{{this.extension}}_FILES {{this.count}}
|
|
58
50
|
{{/each}}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
#include <PsychicHttpsServer.h>
|
|
64
|
-
|
|
65
|
-
//
|
|
51
|
+
`;
|
|
52
|
+
const dataArraysSection = (progmem = false) => {
|
|
53
|
+
const memDirective = progmem ? ' PROGMEM' : '';
|
|
54
|
+
return `
|
|
66
55
|
{{#switch gzip}}
|
|
67
56
|
{{#case "true"}}
|
|
68
57
|
{{#each sources}}
|
|
69
|
-
const uint8_t datagzip_{{this.dataname}}[{{this.lengthGzip}}] = { {{this.bytesGzip}} };
|
|
58
|
+
const uint8_t datagzip_{{this.dataname}}[{{this.lengthGzip}}]${memDirective} = { {{this.bytesGzip}} };
|
|
70
59
|
{{/each}}
|
|
71
60
|
{{/case}}
|
|
72
61
|
{{#case "false"}}
|
|
73
62
|
{{#each sources}}
|
|
74
|
-
const uint8_t data_{{this.dataname}}[{{this.length}}] = { {{this.bytes}} };
|
|
63
|
+
const uint8_t data_{{this.dataname}}[{{this.length}}]${memDirective} = { {{this.bytes}} };
|
|
75
64
|
{{/each}}
|
|
76
65
|
{{/case}}
|
|
77
66
|
{{#case "compiler"}}
|
|
78
67
|
#ifdef {{definePrefix}}_ENABLE_GZIP
|
|
79
68
|
{{#each sources}}
|
|
80
|
-
const uint8_t datagzip_{{this.dataname}}[{{this.lengthGzip}}] = { {{this.bytesGzip}} };
|
|
69
|
+
const uint8_t datagzip_{{this.dataname}}[{{this.lengthGzip}}]${memDirective} = { {{this.bytesGzip}} };
|
|
81
70
|
{{/each}}
|
|
82
71
|
#else
|
|
83
72
|
{{#each sources}}
|
|
84
|
-
const uint8_t data_{{this.dataname}}[{{this.length}}] = { {{this.bytes}} };
|
|
73
|
+
const uint8_t data_{{this.dataname}}[{{this.length}}]${memDirective} = { {{this.bytes}} };
|
|
85
74
|
{{/each}}
|
|
86
|
-
#endif
|
|
75
|
+
#endif
|
|
87
76
|
{{/case}}
|
|
88
77
|
{{/switch}}
|
|
89
|
-
|
|
90
|
-
|
|
78
|
+
`;
|
|
79
|
+
};
|
|
80
|
+
const etagArraysSection = `
|
|
91
81
|
{{#switch etag}}
|
|
92
82
|
{{#case "true"}}
|
|
93
83
|
{{#each sources}}
|
|
@@ -101,9 +91,30 @@ const char * etag_{{this.dataname}} = "{{this.md5}}";
|
|
|
101
91
|
{{#each sources}}
|
|
102
92
|
const char * etag_{{this.dataname}} = "{{this.md5}}";
|
|
103
93
|
{{/each}}
|
|
104
|
-
#endif
|
|
94
|
+
#endif
|
|
105
95
|
{{/case}}
|
|
106
96
|
{{/switch}}
|
|
97
|
+
`;
|
|
98
|
+
const psychicTemplate = `
|
|
99
|
+
//engine: PsychicHttpServer
|
|
100
|
+
//cmdline: {{{commandLine}}}
|
|
101
|
+
//You should use server.config.max_uri_handlers = {{fileCount}}; or higher value to proper handles all files
|
|
102
|
+
{{#if created }}
|
|
103
|
+
//created: {{now}}
|
|
104
|
+
{{/if}}
|
|
105
|
+
//
|
|
106
|
+
${commonHeaderSection}
|
|
107
|
+
|
|
108
|
+
//
|
|
109
|
+
#include <Arduino.h>
|
|
110
|
+
#include <PsychicHttp.h>
|
|
111
|
+
#include <PsychicHttpsServer.h>
|
|
112
|
+
|
|
113
|
+
//
|
|
114
|
+
${dataArraysSection(false)}
|
|
115
|
+
|
|
116
|
+
//
|
|
117
|
+
${etagArraysSection}
|
|
107
118
|
|
|
108
119
|
//
|
|
109
120
|
// Http Handlers
|
|
@@ -115,7 +126,7 @@ void {{methodName}}(PsychicHttpServer * server) {
|
|
|
115
126
|
|
|
116
127
|
{{#switch ../etag}}
|
|
117
128
|
{{#case "true"}}
|
|
118
|
-
if (request->hasHeader("If-None-Match") && request->header("If-None-Match")
|
|
129
|
+
if (request->hasHeader("If-None-Match") && request->header("If-None-Match").equals(etag_{{this.dataname}})) {
|
|
119
130
|
PsychicResponse response304(request);
|
|
120
131
|
response304.setCode(304);
|
|
121
132
|
return response304.send();
|
|
@@ -123,12 +134,12 @@ void {{methodName}}(PsychicHttpServer * server) {
|
|
|
123
134
|
{{/case}}
|
|
124
135
|
{{#case "compiler"}}
|
|
125
136
|
#ifdef {{../definePrefix}}_ENABLE_ETAG
|
|
126
|
-
if (request->hasHeader("If-None-Match") && request->header("If-None-Match")
|
|
137
|
+
if (request->hasHeader("If-None-Match") && request->header("If-None-Match").equals(etag_{{this.dataname}})) {
|
|
127
138
|
PsychicResponse response304(request);
|
|
128
139
|
response304.setCode(304);
|
|
129
140
|
return response304.send();
|
|
130
141
|
}
|
|
131
|
-
#endif
|
|
142
|
+
#endif
|
|
132
143
|
{{/case}}
|
|
133
144
|
{{/switch}}
|
|
134
145
|
|
|
@@ -201,50 +212,7 @@ const psychic2Template = `
|
|
|
201
212
|
//created: {{now}}
|
|
202
213
|
{{/if}}
|
|
203
214
|
//
|
|
204
|
-
|
|
205
|
-
{{#switch etag}}
|
|
206
|
-
{{#case "true"}}
|
|
207
|
-
#ifdef {{definePrefix}}_ENABLE_ETAG
|
|
208
|
-
#warning {{definePrefix}}_ENABLE_ETAG has no effect because it is permanently switched ON
|
|
209
|
-
#endif
|
|
210
|
-
{{/case}}
|
|
211
|
-
{{#case "false"}}
|
|
212
|
-
#ifdef {{definePrefix}}_ENABLE_ETAG
|
|
213
|
-
#warning {{definePrefix}}_ENABLE_ETAG has no effect because it is permanently switched OFF
|
|
214
|
-
#endif
|
|
215
|
-
{{/case}}
|
|
216
|
-
{{/switch}}
|
|
217
|
-
|
|
218
|
-
{{#switch gzip}}
|
|
219
|
-
{{#case "true"}}
|
|
220
|
-
#ifdef {{definePrefix}}_ENABLE_GZIP
|
|
221
|
-
#warning {{definePrefix}}_ENABLE_GZIP has no effect because it is permanently switched ON
|
|
222
|
-
#endif
|
|
223
|
-
{{/case}}
|
|
224
|
-
{{#case "false"}}
|
|
225
|
-
#ifdef {{definePrefix}}_ENABLE_GZIP
|
|
226
|
-
#warning {{definePrefix}}_ENABLE_GZIP has no effect because it is permanently switched OFF
|
|
227
|
-
#endif
|
|
228
|
-
{{/case}}
|
|
229
|
-
{{/switch}}
|
|
230
|
-
|
|
231
|
-
//
|
|
232
|
-
{{#if version }}
|
|
233
|
-
#define {{definePrefix}}_VERSION "{{version}}"
|
|
234
|
-
{{/if}}
|
|
235
|
-
#define {{definePrefix}}_COUNT {{fileCount}}
|
|
236
|
-
#define {{definePrefix}}_SIZE {{fileSize}}
|
|
237
|
-
#define {{definePrefix}}_SIZE_GZIP {{fileGzipSize}}
|
|
238
|
-
|
|
239
|
-
//
|
|
240
|
-
{{#each sources}}
|
|
241
|
-
#define {{../definePrefix}}_FILE_{{this.datanameUpperCase}}
|
|
242
|
-
{{/each}}
|
|
243
|
-
|
|
244
|
-
//
|
|
245
|
-
{{#each filesByExtension}}
|
|
246
|
-
#define {{../definePrefix}}_{{this.extension}}_FILES {{this.count}}
|
|
247
|
-
{{/each}}
|
|
215
|
+
${commonHeaderSection}
|
|
248
216
|
|
|
249
217
|
//
|
|
250
218
|
#include <Arduino.h>
|
|
@@ -252,47 +220,10 @@ const psychic2Template = `
|
|
|
252
220
|
#include <PsychicHttpsServer.h>
|
|
253
221
|
|
|
254
222
|
//
|
|
255
|
-
{
|
|
256
|
-
{{#case "true"}}
|
|
257
|
-
{{#each sources}}
|
|
258
|
-
const uint8_t datagzip_{{this.dataname}}[{{this.lengthGzip}}] = { {{this.bytesGzip}} };
|
|
259
|
-
{{/each}}
|
|
260
|
-
{{/case}}
|
|
261
|
-
{{#case "false"}}
|
|
262
|
-
{{#each sources}}
|
|
263
|
-
const uint8_t data_{{this.dataname}}[{{this.length}}] = { {{this.bytes}} };
|
|
264
|
-
{{/each}}
|
|
265
|
-
{{/case}}
|
|
266
|
-
{{#case "compiler"}}
|
|
267
|
-
#ifdef {{definePrefix}}_ENABLE_GZIP
|
|
268
|
-
{{#each sources}}
|
|
269
|
-
const uint8_t datagzip_{{this.dataname}}[{{this.lengthGzip}}] = { {{this.bytesGzip}} };
|
|
270
|
-
{{/each}}
|
|
271
|
-
#else
|
|
272
|
-
{{#each sources}}
|
|
273
|
-
const uint8_t data_{{this.dataname}}[{{this.length}}] = { {{this.bytes}} };
|
|
274
|
-
{{/each}}
|
|
275
|
-
#endif
|
|
276
|
-
{{/case}}
|
|
277
|
-
{{/switch}}
|
|
223
|
+
${dataArraysSection(false)}
|
|
278
224
|
|
|
279
225
|
//
|
|
280
|
-
{
|
|
281
|
-
{{#case "true"}}
|
|
282
|
-
{{#each sources}}
|
|
283
|
-
const char * etag_{{this.dataname}} = "{{this.md5}}";
|
|
284
|
-
{{/each}}
|
|
285
|
-
{{/case}}
|
|
286
|
-
{{#case "false"}}
|
|
287
|
-
{{/case}}
|
|
288
|
-
{{#case "compiler"}}
|
|
289
|
-
#ifdef {{definePrefix}}_ENABLE_ETAG
|
|
290
|
-
{{#each sources}}
|
|
291
|
-
const char * etag_{{this.dataname}} = "{{this.md5}}";
|
|
292
|
-
{{/each}}
|
|
293
|
-
#endif
|
|
294
|
-
{{/case}}
|
|
295
|
-
{{/switch}}
|
|
226
|
+
${etagArraysSection}
|
|
296
227
|
|
|
297
228
|
//
|
|
298
229
|
// Http Handlers
|
|
@@ -304,18 +235,18 @@ void {{methodName}}(PsychicHttpServer * server) {
|
|
|
304
235
|
|
|
305
236
|
{{#switch ../etag}}
|
|
306
237
|
{{#case "true"}}
|
|
307
|
-
if (request->hasHeader("If-None-Match") && request->header("If-None-Match")
|
|
238
|
+
if (request->hasHeader("If-None-Match") && request->header("If-None-Match").equals(etag_{{this.dataname}})) {
|
|
308
239
|
response->setCode(304);
|
|
309
240
|
return response->send();
|
|
310
241
|
}
|
|
311
242
|
{{/case}}
|
|
312
243
|
{{#case "compiler"}}
|
|
313
244
|
#ifdef {{../definePrefix}}_ENABLE_ETAG
|
|
314
|
-
if (request->hasHeader("If-None-Match") && request->header("If-None-Match")
|
|
245
|
+
if (request->hasHeader("If-None-Match") && request->header("If-None-Match").equals(etag_{{this.dataname}})) {
|
|
315
246
|
response->setCode(304);
|
|
316
247
|
return response->send();
|
|
317
248
|
}
|
|
318
|
-
#endif
|
|
249
|
+
#endif
|
|
319
250
|
{{/case}}
|
|
320
251
|
{{/switch}}
|
|
321
252
|
|
|
@@ -387,120 +318,111 @@ const asyncTemplate = `
|
|
|
387
318
|
//created: {{now}}
|
|
388
319
|
{{/if}}
|
|
389
320
|
//
|
|
321
|
+
${commonHeaderSection}
|
|
390
322
|
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
#
|
|
394
|
-
#warning {{definePrefix}}_ENABLE_ETAG has no effect because it is permanently switched ON
|
|
395
|
-
#endif
|
|
396
|
-
{{/case}}
|
|
397
|
-
{{#case "false"}}
|
|
398
|
-
#ifdef {{definePrefix}}_ENABLE_ETAG
|
|
399
|
-
#warning {{definePrefix}}_ENABLE_ETAG has no effect because it is permanently switched OFF
|
|
400
|
-
#endif
|
|
401
|
-
{{/case}}
|
|
402
|
-
{{/switch}}
|
|
323
|
+
//
|
|
324
|
+
#include <Arduino.h>
|
|
325
|
+
#include <ESPAsyncWebServer.h>
|
|
403
326
|
|
|
404
|
-
|
|
405
|
-
{
|
|
406
|
-
#ifdef {{definePrefix}}_ENABLE_GZIP
|
|
407
|
-
#warning {{definePrefix}}_ENABLE_GZIP has no effect because it is permanently switched ON
|
|
408
|
-
#endif
|
|
409
|
-
{{/case}}
|
|
410
|
-
{{#case "false"}}
|
|
411
|
-
#ifdef {{definePrefix}}_ENABLE_GZIP
|
|
412
|
-
#warning {{definePrefix}}_ENABLE_GZIP has no effect because it is permanently switched OFF
|
|
413
|
-
#endif
|
|
414
|
-
{{/case}}
|
|
415
|
-
{{/switch}}
|
|
327
|
+
//
|
|
328
|
+
${dataArraysSection(true)}
|
|
416
329
|
|
|
417
330
|
//
|
|
418
|
-
{
|
|
419
|
-
#define {{definePrefix}}_VERSION "{{version}}"
|
|
420
|
-
{{/if}}
|
|
421
|
-
#define {{definePrefix}}_COUNT {{fileCount}}
|
|
422
|
-
#define {{definePrefix}}_SIZE {{fileSize}}
|
|
423
|
-
#define {{definePrefix}}_SIZE_GZIP {{fileGzipSize}}
|
|
331
|
+
${etagArraysSection}
|
|
424
332
|
|
|
425
333
|
//
|
|
334
|
+
// Http Handlers
|
|
335
|
+
void {{methodName}}(AsyncWebServer * server) {
|
|
426
336
|
{{#each sources}}
|
|
427
|
-
#define {{../definePrefix}}_FILE_{{this.datanameUpperCase}}
|
|
428
|
-
{{/each}}
|
|
429
|
-
|
|
430
337
|
//
|
|
431
|
-
{{
|
|
432
|
-
|
|
433
|
-
{{/each}}
|
|
338
|
+
// {{this.filename}}
|
|
339
|
+
server->on("/{{this.filename}}", HTTP_GET, [](AsyncWebServerRequest * request) {
|
|
434
340
|
|
|
435
|
-
|
|
436
|
-
#
|
|
437
|
-
|
|
341
|
+
{{#switch ../etag}}
|
|
342
|
+
{{#case "true"}}
|
|
343
|
+
const AsyncWebHeader* h = request->getHeader("If-None-Match");
|
|
344
|
+
if (h && h->value().equals(etag_{{this.dataname}})) {
|
|
345
|
+
request->send(304);
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
{{/case}}
|
|
349
|
+
{{#case "compiler"}}
|
|
350
|
+
#ifdef {{../definePrefix}}_ENABLE_ETAG
|
|
351
|
+
const AsyncWebHeader* h = request->getHeader("If-None-Match");
|
|
352
|
+
if (h && h->value().equals(etag_{{this.dataname}})) {
|
|
353
|
+
request->send(304);
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
#endif
|
|
357
|
+
{{/case}}
|
|
358
|
+
{{/switch}}
|
|
438
359
|
|
|
439
|
-
|
|
440
|
-
{{#switch gzip}}
|
|
360
|
+
{{#switch ../gzip}}
|
|
441
361
|
{{#case "true"}}
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
362
|
+
AsyncWebServerResponse *response = request->beginResponse(200, "{{this.mime}}", datagzip_{{this.dataname}}, {{this.lengthGzip}});
|
|
363
|
+
{{#if this.isGzip}}
|
|
364
|
+
response->addHeader("Content-Encoding", "gzip");
|
|
365
|
+
{{/if}}
|
|
445
366
|
{{/case}}
|
|
446
367
|
{{#case "false"}}
|
|
447
|
-
|
|
448
|
-
const uint8_t data_{{this.dataname}}[{{this.length}}] PROGMEM = { {{this.bytes}} };
|
|
449
|
-
{{/each}}
|
|
368
|
+
AsyncWebServerResponse *response = request->beginResponse(200, "{{this.mime}}", data_{{this.dataname}}, {{this.length}});
|
|
450
369
|
{{/case}}
|
|
451
370
|
{{#case "compiler"}}
|
|
452
|
-
#ifdef {{definePrefix}}_ENABLE_GZIP
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
#endif
|
|
371
|
+
#ifdef {{../definePrefix}}_ENABLE_GZIP
|
|
372
|
+
AsyncWebServerResponse *response = request->beginResponse(200, "{{this.mime}}", datagzip_{{this.dataname}}, {{this.lengthGzip}});
|
|
373
|
+
{{#if this.isGzip}}
|
|
374
|
+
response->addHeader("Content-Encoding", "gzip");
|
|
375
|
+
{{/if}}
|
|
376
|
+
#else
|
|
377
|
+
AsyncWebServerResponse *response = request->beginResponse(200, "{{this.mime}}", data_{{this.dataname}}, {{this.length}});
|
|
378
|
+
#endif
|
|
461
379
|
{{/case}}
|
|
462
380
|
{{/switch}}
|
|
463
381
|
|
|
464
|
-
|
|
465
|
-
{{#switch etag}}
|
|
382
|
+
{{#switch ../etag}}
|
|
466
383
|
{{#case "true"}}
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
{{
|
|
471
|
-
|
|
384
|
+
{{#../cacheTime}}
|
|
385
|
+
response->addHeader("Cache-Control", "max-age={{value}}");
|
|
386
|
+
{{/../cacheTime}}
|
|
387
|
+
{{^../cacheTime}}
|
|
388
|
+
response->addHeader("Cache-Control", "no-cache");
|
|
389
|
+
{{/../cacheTime}}
|
|
390
|
+
response->addHeader("ETag", etag_{{this.dataname}});
|
|
472
391
|
{{/case}}
|
|
473
392
|
{{#case "compiler"}}
|
|
474
|
-
#ifdef {{definePrefix}}_ENABLE_ETAG
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
393
|
+
#ifdef {{../definePrefix}}_ENABLE_ETAG
|
|
394
|
+
{{#../cacheTime}}
|
|
395
|
+
response->addHeader("Cache-Control", "max-age={{value}}");
|
|
396
|
+
{{/../cacheTime}}
|
|
397
|
+
{{^../cacheTime}}
|
|
398
|
+
response->addHeader("Cache-Control", "no-cache");
|
|
399
|
+
{{/../cacheTime}}
|
|
400
|
+
response->addHeader("ETag", etag_{{this.dataname}});
|
|
401
|
+
#endif
|
|
479
402
|
{{/case}}
|
|
480
403
|
{{/switch}}
|
|
481
404
|
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
{
|
|
486
|
-
//
|
|
487
|
-
// {{this.filename}}
|
|
488
|
-
ArRequestHandlerFunction func_{{this.dataname}} = [](AsyncWebServerRequest * request) {
|
|
405
|
+
request->send(response);
|
|
406
|
+
});
|
|
407
|
+
{{#if this.isDefault}}
|
|
408
|
+
server->on("/", HTTP_GET, [](AsyncWebServerRequest * request) {
|
|
489
409
|
|
|
490
410
|
{{#switch ../etag}}
|
|
491
411
|
{{#case "true"}}
|
|
492
|
-
|
|
412
|
+
const AsyncWebHeader* h = request->getHeader("If-None-Match");
|
|
413
|
+
if (h && h->value().equals(etag_{{this.dataname}})) {
|
|
493
414
|
request->send(304);
|
|
494
415
|
return;
|
|
495
416
|
}
|
|
496
417
|
{{/case}}
|
|
497
418
|
{{#case "compiler"}}
|
|
498
419
|
#ifdef {{../definePrefix}}_ENABLE_ETAG
|
|
499
|
-
|
|
420
|
+
const AsyncWebHeader* h = request->getHeader("If-None-Match");
|
|
421
|
+
if (h && h->value().equals(etag_{{this.dataname}})) {
|
|
500
422
|
request->send(304);
|
|
501
423
|
return;
|
|
502
424
|
}
|
|
503
|
-
#endif
|
|
425
|
+
#endif
|
|
504
426
|
{{/case}}
|
|
505
427
|
{{/switch}}
|
|
506
428
|
|
|
@@ -522,7 +444,7 @@ void {{methodName}}(AsyncWebServer * server) {
|
|
|
522
444
|
{{/if}}
|
|
523
445
|
#else
|
|
524
446
|
AsyncWebServerResponse *response = request->beginResponse(200, "{{this.mime}}", data_{{this.dataname}}, {{this.length}});
|
|
525
|
-
#endif
|
|
447
|
+
#endif
|
|
526
448
|
{{/case}}
|
|
527
449
|
{{/switch}}
|
|
528
450
|
|
|
@@ -545,15 +467,12 @@ void {{methodName}}(AsyncWebServer * server) {
|
|
|
545
467
|
response->addHeader("Cache-Control", "no-cache");
|
|
546
468
|
{{/../cacheTime}}
|
|
547
469
|
response->addHeader("ETag", etag_{{this.dataname}});
|
|
548
|
-
#endif
|
|
470
|
+
#endif
|
|
549
471
|
{{/case}}
|
|
550
472
|
{{/switch}}
|
|
551
473
|
|
|
552
474
|
request->send(response);
|
|
553
|
-
};
|
|
554
|
-
server->on("/{{this.filename}}", HTTP_GET, func_{{this.dataname}});
|
|
555
|
-
{{#if this.isDefault}}
|
|
556
|
-
server->on("/", HTTP_GET, func_{{this.dataname}});
|
|
475
|
+
});
|
|
557
476
|
{{/if}}
|
|
558
477
|
|
|
559
478
|
{{/each}}
|
|
@@ -570,33 +489,26 @@ const getTemplate = (engine) => {
|
|
|
570
489
|
return asyncTemplate;
|
|
571
490
|
}
|
|
572
491
|
};
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
})
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
created: commandLine_1.cmdLine.created,
|
|
592
|
-
version: commandLine_1.cmdLine.version,
|
|
593
|
-
methodName: commandLine_1.cmdLine.espmethod,
|
|
594
|
-
cacheTime: commandLine_1.cmdLine.cachetime ? { value: commandLine_1.cmdLine.cachetime } : undefined,
|
|
595
|
-
definePrefix: commandLine_1.cmdLine.define
|
|
596
|
-
}, {
|
|
597
|
-
helpers: {
|
|
492
|
+
const transformSourceToTemplateData = (s) => ({
|
|
493
|
+
...s,
|
|
494
|
+
length: s.content.length,
|
|
495
|
+
bytes: [...s.content].map((v) => `${v.toString(10)}`).join(','),
|
|
496
|
+
lengthGzip: s.contentGzip.length,
|
|
497
|
+
bytesGzip: [...s.contentGzip].map((v) => `${v.toString(10)}`).join(','),
|
|
498
|
+
isDefault: s.filename.startsWith('index.htm')
|
|
499
|
+
});
|
|
500
|
+
const postProcessCppCode = (code) => code
|
|
501
|
+
.split('\n')
|
|
502
|
+
.map((line) => line.trimEnd())
|
|
503
|
+
.filter(Boolean)
|
|
504
|
+
.map((line) => (line === '//' ? '' : line))
|
|
505
|
+
.join('\n')
|
|
506
|
+
.replace(/\\n{2}/, '\n');
|
|
507
|
+
const createHandlebarsHelpers = () => {
|
|
508
|
+
let switchValue;
|
|
509
|
+
return {
|
|
598
510
|
ifeq: function (a, b, options) {
|
|
599
|
-
if (a
|
|
511
|
+
if (a === b)
|
|
600
512
|
return options.fn(this);
|
|
601
513
|
return options.inverse(this);
|
|
602
514
|
},
|
|
@@ -605,16 +517,31 @@ const getCppCode = (sources, filesByExtension) => (0, handlebars_1.compile)(getT
|
|
|
605
517
|
return options.fn(this);
|
|
606
518
|
},
|
|
607
519
|
case: function (value, options) {
|
|
608
|
-
if (value
|
|
520
|
+
if (value === switchValue)
|
|
609
521
|
return options.fn(this);
|
|
610
522
|
return options.inverse(this);
|
|
611
523
|
}
|
|
612
|
-
}
|
|
613
|
-
}
|
|
614
|
-
|
|
615
|
-
.
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
524
|
+
};
|
|
525
|
+
};
|
|
526
|
+
const getCppCode = (sources, filesByExtension) => {
|
|
527
|
+
const template = (0, handlebars_1.compile)(getTemplate(commandLine_1.cmdLine.engine));
|
|
528
|
+
const templateData = {
|
|
529
|
+
commandLine: process.argv.slice(2).join(' '),
|
|
530
|
+
now: `${new Date().toLocaleDateString()} ${new Date().toLocaleTimeString()}`,
|
|
531
|
+
fileCount: sources.length.toString(),
|
|
532
|
+
fileSize: sources.reduce((previous, current) => previous + current.content.length, 0).toString(),
|
|
533
|
+
fileGzipSize: sources.reduce((previous, current) => previous + current.contentGzip.length, 0).toString(),
|
|
534
|
+
sources: sources.map((s) => transformSourceToTemplateData(s)),
|
|
535
|
+
filesByExtension,
|
|
536
|
+
etag: commandLine_1.cmdLine.etag,
|
|
537
|
+
gzip: commandLine_1.cmdLine.gzip,
|
|
538
|
+
created: commandLine_1.cmdLine.created,
|
|
539
|
+
version: commandLine_1.cmdLine.version,
|
|
540
|
+
methodName: commandLine_1.cmdLine.espmethod,
|
|
541
|
+
cacheTime: commandLine_1.cmdLine.cachetime ? { value: commandLine_1.cmdLine.cachetime } : undefined,
|
|
542
|
+
definePrefix: commandLine_1.cmdLine.define
|
|
543
|
+
};
|
|
544
|
+
const rawCode = template(templateData, { helpers: createHandlebarsHelpers() });
|
|
545
|
+
return postProcessCppCode(rawCode);
|
|
546
|
+
};
|
|
620
547
|
exports.getCppCode = getCppCode;
|
package/dist/cppCodeEspIdf.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const espidfTemplate = "\n//engine: espidf\n//cmdline: {{{commandLine}}}\n{{#if created }}\n//created: {{now}}\n{{/if}}\n//\n\n{{#switch etag}}\n{{#case \"true\"}}\n#ifdef {{definePrefix}}_ENABLE_ETAG\n#warning {{definePrefix}}_ENABLE_ETAG has no effect because it is permanently switched ON\n#endif\n{{/case}}\n{{#case \"false\"}}\n#ifdef {{definePrefix}}_ENABLE_ETAG\n#warning {{definePrefix}}_ENABLE_ETAG has no effect because it is permanently switched OFF\n#endif\n{{/case}}\n{{/switch}}\n\n{{#switch gzip}}\n{{#case \"true\"}}\n#ifdef {{definePrefix}}_ENABLE_GZIP\n#warning {{definePrefix}}_ENABLE_GZIP has no effect because it is permanently switched ON\n#endif\n{{/case}}\n{{#case \"false\"}}\n#ifdef {{definePrefix}}_ENABLE_GZIP\n#warning {{definePrefix}}_ENABLE_GZIP has no effect because it is permanently switched OFF\n#endif\n{{/case}}\n{{/switch}}\n\n//\n{{#if version }}\n#define {{definePrefix}}_VERSION \"{{version}}\"\n{{/if}}\n#define {{definePrefix}}_COUNT {{fileCount}}\n#define {{definePrefix}}_SIZE {{fileSize}}\n#define {{definePrefix}}_SIZE_GZIP {{fileGzipSize}}\n\n//\n{{#each sources}}\n#define {{../definePrefix}}_FILE_{{this.datanameUpperCase}}\n{{/each}}\n\n//\n{{#each filesByExtension}}\n#define {{../definePrefix}}_{{this.extension}}_FILES {{this.count}}\n{{/each}}\n\n#include <stdint.h>\n#include <esp_err.h>\n#include <esp_http_server.h>\n\n//\n{{#switch gzip}}\n{{#case \"true\"}}\n {{#each sources}}\nconst char datagzip_{{this.dataname}}[{{this.lengthGzip}}] = { {{this.bytesGzip}} };\n {{/each}}\n{{/case}}\n{{#case \"false\"}}\n {{#each sources}}\nconst char data_{{this.dataname}}[{{this.length}}] = { {{this.bytes}} };\n {{/each}}\n{{/case}}\n{{#case \"compiler\"}}\n#ifdef {{definePrefix}}_ENABLE_GZIP\n {{#each sources}}\nconst char datagzip_{{this.dataname}}[{{this.lengthGzip}}] = { {{this.bytesGzip}} };\n {{/each}}\n#else\n {{#each sources}}\nconst char data_{{this.dataname}}[{{this.length}}] = { {{this.bytes}} };\n {{/each}}\n#endif \n{{/case}}\n{{/switch}}\n\n//\n{{#switch etag}}\n{{#case \"true\"}}\n {{#each sources}}\nconst char * etag_{{this.dataname}} = \"{{this.md5}}\";\n {{/each}}\n{{/case}}\n{{#case \"false\"}}\n{{/case}}\n{{#case \"compiler\"}}\n#ifdef {{definePrefix}}_ENABLE_ETAG\n {{#each sources}}\nconst char * etag_{{this.dataname}} = \"{{this.md5}}\";\n {{/each}}\n#endif \n{{/case}}\n{{/switch}}\n\n{{#each sources}}\n\nstatic esp_err_t file_handler_{{this.datanameUpperCase}} (httpd_req_t *req)\n{\n httpd_resp_set_type(req, \"{{this.mime}}\");\n{{#switch ../gzip}}\n{{#case \"true\"}}\n{{#if this.isGzip}}\n httpd_resp_set_hdr(req, \"Content-Encoding\", \"gzip\");\n{{/if}}\n{{/case}}\n{{#case \"compiler\"}}\n {{#if this.isGzip}}\n #ifdef {{../definePrefix}}_ENABLE_GZIP\n httpd_resp_set_hdr(req, \"Content-Encoding\", \"gzip\");\n #endif \n {{/if}}\n{{/case}}\n{{/switch}}\n\n{{#switch ../etag}}\n{{#case \"true\"}}\n{{#../cacheTime}}\n httpd_resp_set_hdr(req, \"Cache-Control\", \"max-age={{value}}\");\n{{/../cacheTime}}\n{{^../cacheTime}}\n httpd_resp_set_hdr(req, \"Cache-Control\", \"no-cache\");\n{{/../cacheTime}}\n httpd_resp_set_hdr(req, \"ETag\", etag_{{this.dataname}});\n{{/case}}\n{{#case \"compiler\"}}\n #ifdef {{../definePrefix}}_ENABLE_ETAG\n{{#../cacheTime}}\n httpd_resp_set_hdr(req, \"Cache-Control\", \"max-age={{value}}\");\n{{/../cacheTime}}\n{{^../cacheTime}}\n httpd_resp_set_hdr(req, \"Cache-Control\", \"no-cache\");\n{{/../cacheTime}}\n httpd_resp_set_hdr(req, \"ETag\", etag_{{this.dataname}});\n #endif \n{{/case}}\n{{/switch}}\n\n{{#switch ../gzip}}\n{{#case \"true\"}}\n httpd_resp_send(req, datagzip_{{this.dataname}}, {{this.lengthGzip}});\n{{/case}}\n{{#case \"false\"}}\n httpd_resp_send(req, data_{{this.dataname}}, {{this.length}});\n{{/case}}\n{{#case \"compiler\"}}\n #ifdef {{../definePrefix}}_ENABLE_GZIP\n httpd_resp_send(req, datagzip_{{this.dataname}}, {{this.lengthGzip}});\n #else\n httpd_resp_send(req, data_{{this.dataname}}, {{this.length}});\n #endif \n{{/case}}\n{{/switch}}\n return ESP_OK;\n}\n\n{{#if this.isDefault}}\nstatic const httpd_uri_t route_def_{{this.datanameUpperCase}} = {\n .uri = \"/\",\n .method = HTTP_GET,\n .handler = file_handler_{{this.datanameUpperCase}},\n};\n{{/if}}\n\nstatic const httpd_uri_t route_{{this.datanameUpperCase}} = {\n .uri = \"/{{this.filename}}\",\n .method = HTTP_GET,\n .handler = file_handler_{{this.datanameUpperCase}},\n};\n\n{{/each}}\n\n\n\nstatic inline void {{methodName}}(httpd_handle_t server) {\n{{#each sources}}\n{{#if this.isDefault}}\n httpd_register_uri_handler(server, &route_def_{{this.datanameUpperCase}});\n{{/if}}\n httpd_register_uri_handler(server, &route_{{this.datanameUpperCase}});\n{{/each}}\n\n}";
|
|
1
|
+
export declare const espidfTemplate = "\n//engine: espidf\n//cmdline: {{{commandLine}}}\n{{#if created }}\n//created: {{now}}\n{{/if}}\n//\n\n{{#switch etag}}\n{{#case \"true\"}}\n#ifdef {{definePrefix}}_ENABLE_ETAG\n#warning {{definePrefix}}_ENABLE_ETAG has no effect because it is permanently switched ON\n#endif\n{{/case}}\n{{#case \"false\"}}\n#ifdef {{definePrefix}}_ENABLE_ETAG\n#warning {{definePrefix}}_ENABLE_ETAG has no effect because it is permanently switched OFF\n#endif\n{{/case}}\n{{/switch}}\n\n{{#switch gzip}}\n{{#case \"true\"}}\n#ifdef {{definePrefix}}_ENABLE_GZIP\n#warning {{definePrefix}}_ENABLE_GZIP has no effect because it is permanently switched ON\n#endif\n{{/case}}\n{{#case \"false\"}}\n#ifdef {{definePrefix}}_ENABLE_GZIP\n#warning {{definePrefix}}_ENABLE_GZIP has no effect because it is permanently switched OFF\n#endif\n{{/case}}\n{{/switch}}\n\n//\n{{#if version }}\n#define {{definePrefix}}_VERSION \"{{version}}\"\n{{/if}}\n#define {{definePrefix}}_COUNT {{fileCount}}\n#define {{definePrefix}}_SIZE {{fileSize}}\n#define {{definePrefix}}_SIZE_GZIP {{fileGzipSize}}\n\n//\n{{#each sources}}\n#define {{../definePrefix}}_FILE_{{this.datanameUpperCase}}\n{{/each}}\n\n//\n{{#each filesByExtension}}\n#define {{../definePrefix}}_{{this.extension}}_FILES {{this.count}}\n{{/each}}\n\n#include <stdint.h>\n#include <string.h>\n#include <stdlib.h>\n#include <esp_err.h>\n#include <esp_http_server.h>\n\n//\n{{#switch gzip}}\n{{#case \"true\"}}\n {{#each sources}}\nconst char datagzip_{{this.dataname}}[{{this.lengthGzip}}] = { {{this.bytesGzip}} };\n {{/each}}\n{{/case}}\n{{#case \"false\"}}\n {{#each sources}}\nconst char data_{{this.dataname}}[{{this.length}}] = { {{this.bytes}} };\n {{/each}}\n{{/case}}\n{{#case \"compiler\"}}\n#ifdef {{definePrefix}}_ENABLE_GZIP\n {{#each sources}}\nconst char datagzip_{{this.dataname}}[{{this.lengthGzip}}] = { {{this.bytesGzip}} };\n {{/each}}\n#else\n {{#each sources}}\nconst char data_{{this.dataname}}[{{this.length}}] = { {{this.bytes}} };\n {{/each}}\n#endif \n{{/case}}\n{{/switch}}\n\n//\n{{#switch etag}}\n{{#case \"true\"}}\n {{#each sources}}\nconst char * etag_{{this.dataname}} = \"{{this.md5}}\";\n {{/each}}\n{{/case}}\n{{#case \"false\"}}\n{{/case}}\n{{#case \"compiler\"}}\n#ifdef {{definePrefix}}_ENABLE_ETAG\n {{#each sources}}\nconst char * etag_{{this.dataname}} = \"{{this.md5}}\";\n {{/each}}\n#endif \n{{/case}}\n{{/switch}}\n\n{{#each sources}}\n\nstatic esp_err_t file_handler_{{this.datanameUpperCase}} (httpd_req_t *req)\n{\n{{#switch ../etag}}\n{{#case \"true\"}}\n size_t hdr_len = httpd_req_get_hdr_value_len(req, \"If-None-Match\");\n if (hdr_len > 0) {\n char* hdr_value = malloc(hdr_len + 1);\n if (httpd_req_get_hdr_value_str(req, \"If-None-Match\", hdr_value, hdr_len + 1) == ESP_OK) {\n if (strcmp(hdr_value, etag_{{this.dataname}}) == 0) {\n free(hdr_value);\n httpd_resp_set_status(req, \"304 Not Modified\");\n httpd_resp_send(req, NULL, 0);\n return ESP_OK;\n }\n }\n free(hdr_value);\n }\n{{/case}}\n{{#case \"compiler\"}}\n #ifdef {{../definePrefix}}_ENABLE_ETAG\n size_t hdr_len = httpd_req_get_hdr_value_len(req, \"If-None-Match\");\n if (hdr_len > 0) {\n char* hdr_value = malloc(hdr_len + 1);\n if (httpd_req_get_hdr_value_str(req, \"If-None-Match\", hdr_value, hdr_len + 1) == ESP_OK) {\n if (strcmp(hdr_value, etag_{{this.dataname}}) == 0) {\n free(hdr_value);\n httpd_resp_set_status(req, \"304 Not Modified\");\n httpd_resp_send(req, NULL, 0);\n return ESP_OK;\n }\n }\n free(hdr_value);\n }\n #endif\n{{/case}}\n{{/switch}}\n httpd_resp_set_type(req, \"{{this.mime}}\");\n{{#switch ../gzip}}\n{{#case \"true\"}}\n{{#if this.isGzip}}\n httpd_resp_set_hdr(req, \"Content-Encoding\", \"gzip\");\n{{/if}}\n{{/case}}\n{{#case \"compiler\"}}\n {{#if this.isGzip}}\n #ifdef {{../definePrefix}}_ENABLE_GZIP\n httpd_resp_set_hdr(req, \"Content-Encoding\", \"gzip\");\n #endif \n {{/if}}\n{{/case}}\n{{/switch}}\n\n{{#switch ../etag}}\n{{#case \"true\"}}\n{{#../cacheTime}}\n httpd_resp_set_hdr(req, \"Cache-Control\", \"max-age={{value}}\");\n{{/../cacheTime}}\n{{^../cacheTime}}\n httpd_resp_set_hdr(req, \"Cache-Control\", \"no-cache\");\n{{/../cacheTime}}\n httpd_resp_set_hdr(req, \"ETag\", etag_{{this.dataname}});\n{{/case}}\n{{#case \"compiler\"}}\n #ifdef {{../definePrefix}}_ENABLE_ETAG\n{{#../cacheTime}}\n httpd_resp_set_hdr(req, \"Cache-Control\", \"max-age={{value}}\");\n{{/../cacheTime}}\n{{^../cacheTime}}\n httpd_resp_set_hdr(req, \"Cache-Control\", \"no-cache\");\n{{/../cacheTime}}\n httpd_resp_set_hdr(req, \"ETag\", etag_{{this.dataname}});\n #endif \n{{/case}}\n{{/switch}}\n\n{{#switch ../gzip}}\n{{#case \"true\"}}\n httpd_resp_send(req, datagzip_{{this.dataname}}, {{this.lengthGzip}});\n{{/case}}\n{{#case \"false\"}}\n httpd_resp_send(req, data_{{this.dataname}}, {{this.length}});\n{{/case}}\n{{#case \"compiler\"}}\n #ifdef {{../definePrefix}}_ENABLE_GZIP\n httpd_resp_send(req, datagzip_{{this.dataname}}, {{this.lengthGzip}});\n #else\n httpd_resp_send(req, data_{{this.dataname}}, {{this.length}});\n #endif \n{{/case}}\n{{/switch}}\n return ESP_OK;\n}\n\n{{#if this.isDefault}}\nstatic const httpd_uri_t route_def_{{this.datanameUpperCase}} = {\n .uri = \"/\",\n .method = HTTP_GET,\n .handler = file_handler_{{this.datanameUpperCase}},\n};\n{{/if}}\n\nstatic const httpd_uri_t route_{{this.datanameUpperCase}} = {\n .uri = \"/{{this.filename}}\",\n .method = HTTP_GET,\n .handler = file_handler_{{this.datanameUpperCase}},\n};\n\n{{/each}}\n\n\n\nstatic inline void {{methodName}}(httpd_handle_t server) {\n{{#each sources}}\n{{#if this.isDefault}}\n httpd_register_uri_handler(server, &route_def_{{this.datanameUpperCase}});\n{{/if}}\n httpd_register_uri_handler(server, &route_{{this.datanameUpperCase}});\n{{/each}}\n\n}";
|
package/dist/cppCodeEspIdf.js
CHANGED
|
@@ -54,6 +54,8 @@ exports.espidfTemplate = `
|
|
|
54
54
|
{{/each}}
|
|
55
55
|
|
|
56
56
|
#include <stdint.h>
|
|
57
|
+
#include <string.h>
|
|
58
|
+
#include <stdlib.h>
|
|
57
59
|
#include <esp_err.h>
|
|
58
60
|
#include <esp_http_server.h>
|
|
59
61
|
|
|
@@ -104,6 +106,40 @@ const char * etag_{{this.dataname}} = "{{this.md5}}";
|
|
|
104
106
|
|
|
105
107
|
static esp_err_t file_handler_{{this.datanameUpperCase}} (httpd_req_t *req)
|
|
106
108
|
{
|
|
109
|
+
{{#switch ../etag}}
|
|
110
|
+
{{#case "true"}}
|
|
111
|
+
size_t hdr_len = httpd_req_get_hdr_value_len(req, "If-None-Match");
|
|
112
|
+
if (hdr_len > 0) {
|
|
113
|
+
char* hdr_value = malloc(hdr_len + 1);
|
|
114
|
+
if (httpd_req_get_hdr_value_str(req, "If-None-Match", hdr_value, hdr_len + 1) == ESP_OK) {
|
|
115
|
+
if (strcmp(hdr_value, etag_{{this.dataname}}) == 0) {
|
|
116
|
+
free(hdr_value);
|
|
117
|
+
httpd_resp_set_status(req, "304 Not Modified");
|
|
118
|
+
httpd_resp_send(req, NULL, 0);
|
|
119
|
+
return ESP_OK;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
free(hdr_value);
|
|
123
|
+
}
|
|
124
|
+
{{/case}}
|
|
125
|
+
{{#case "compiler"}}
|
|
126
|
+
#ifdef {{../definePrefix}}_ENABLE_ETAG
|
|
127
|
+
size_t hdr_len = httpd_req_get_hdr_value_len(req, "If-None-Match");
|
|
128
|
+
if (hdr_len > 0) {
|
|
129
|
+
char* hdr_value = malloc(hdr_len + 1);
|
|
130
|
+
if (httpd_req_get_hdr_value_str(req, "If-None-Match", hdr_value, hdr_len + 1) == ESP_OK) {
|
|
131
|
+
if (strcmp(hdr_value, etag_{{this.dataname}}) == 0) {
|
|
132
|
+
free(hdr_value);
|
|
133
|
+
httpd_resp_set_status(req, "304 Not Modified");
|
|
134
|
+
httpd_resp_send(req, NULL, 0);
|
|
135
|
+
return ESP_OK;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
free(hdr_value);
|
|
139
|
+
}
|
|
140
|
+
#endif
|
|
141
|
+
{{/case}}
|
|
142
|
+
{{/switch}}
|
|
107
143
|
httpd_resp_set_type(req, "{{this.mime}}");
|
|
108
144
|
{{#switch ../gzip}}
|
|
109
145
|
{{#case "true"}}
|
package/dist/file.js
CHANGED
|
@@ -14,35 +14,46 @@ const findSimilarFiles = (files) => {
|
|
|
14
14
|
const contentComparer = new Map();
|
|
15
15
|
for (const [filename, content] of files.entries()) {
|
|
16
16
|
const hash = (0, node_crypto_1.createHash)('sha256').update(content).digest('hex');
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
const existingFiles = contentComparer.get(hash);
|
|
18
|
+
if (existingFiles) {
|
|
19
|
+
existingFiles.push(filename);
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
20
22
|
contentComparer.set(hash, [filename]);
|
|
23
|
+
}
|
|
21
24
|
}
|
|
22
25
|
const result = [];
|
|
23
|
-
for (const filenames of contentComparer.values())
|
|
24
|
-
if (filenames.length > 1)
|
|
26
|
+
for (const filenames of contentComparer.values()) {
|
|
27
|
+
if (filenames.length > 1) {
|
|
25
28
|
result.push(filenames);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
26
31
|
return result;
|
|
27
32
|
};
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
return false;
|
|
37
|
-
}
|
|
33
|
+
const shouldSkipFile = (filename, allFilenames) => {
|
|
34
|
+
const extension = node_path_1.default.extname(filename);
|
|
35
|
+
const compressedExtensions = ['.gz', '.brottli', '.br'];
|
|
36
|
+
if (compressedExtensions.includes(extension)) {
|
|
37
|
+
const original = filename.slice(0, -1 * extension.length);
|
|
38
|
+
if (allFilenames.includes(original)) {
|
|
39
|
+
console.log((0, consoleColor_1.redLog)(` ${filename} skipped because is perhaps a compressed version of ${original}`));
|
|
40
|
+
return true;
|
|
38
41
|
}
|
|
39
|
-
|
|
40
|
-
|
|
42
|
+
}
|
|
43
|
+
return false;
|
|
44
|
+
};
|
|
45
|
+
const getFiles = () => {
|
|
46
|
+
const allFilenames = (0, glob_1.globSync)('**/*', { cwd: commandLine_1.cmdLine.sourcepath, nodir: true });
|
|
47
|
+
const filenames = allFilenames.filter((filename) => !shouldSkipFile(filename, allFilenames));
|
|
41
48
|
const result = new Map();
|
|
42
|
-
for (const filename of filenames)
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
49
|
+
for (const filename of filenames) {
|
|
50
|
+
const filePath = node_path_1.default.join(commandLine_1.cmdLine.sourcepath, filename);
|
|
51
|
+
result.set(filename, (0, node_fs_1.readFileSync)(filePath, { flag: 'r' }));
|
|
52
|
+
}
|
|
53
|
+
const duplicates = findSimilarFiles(result);
|
|
54
|
+
for (const sameFiles of duplicates) {
|
|
55
|
+
console.log((0, consoleColor_1.yellowLog)(` ${sameFiles.join(', ')} files look like identical`));
|
|
56
|
+
}
|
|
46
57
|
return result;
|
|
47
58
|
};
|
|
48
59
|
exports.getFiles = getFiles;
|
package/dist/index.js
CHANGED
|
@@ -12,6 +12,8 @@ const commandLine_1 = require("./commandLine");
|
|
|
12
12
|
const consoleColor_1 = require("./consoleColor");
|
|
13
13
|
const cppCode_1 = require("./cppCode");
|
|
14
14
|
const file_1 = require("./file");
|
|
15
|
+
const GZIP_MIN_SIZE = 1024;
|
|
16
|
+
const GZIP_MIN_REDUCTION_RATIO = 0.85;
|
|
15
17
|
const summary = {
|
|
16
18
|
filecount: 0,
|
|
17
19
|
size: 0,
|
|
@@ -19,6 +21,36 @@ const summary = {
|
|
|
19
21
|
};
|
|
20
22
|
const sources = [];
|
|
21
23
|
const filesByExtension = [];
|
|
24
|
+
const shouldUseGzip = (originalSize, compressedSize) => originalSize > GZIP_MIN_SIZE && compressedSize < originalSize * GZIP_MIN_REDUCTION_RATIO;
|
|
25
|
+
const calculateCompressionRatio = (originalSize, compressedSize) => Math.round((compressedSize / originalSize) * 100);
|
|
26
|
+
const formatCompressionLog = (filename, padding, originalSize, compressedSize, useGzip) => {
|
|
27
|
+
const ratio = calculateCompressionRatio(originalSize, compressedSize);
|
|
28
|
+
const sizeInfo = `(${originalSize} -> ${compressedSize} = ${ratio}%)`;
|
|
29
|
+
if (useGzip) {
|
|
30
|
+
return (0, consoleColor_1.greenLog)(` [${filename}] ${padding} ✓ gzip used ${sizeInfo}`);
|
|
31
|
+
}
|
|
32
|
+
const tooSmall = originalSize <= GZIP_MIN_SIZE ? '(too small) ' : '';
|
|
33
|
+
return (0, consoleColor_1.yellowLog)(` [${filename}] ${padding} x gzip unused ${tooSmall}${sizeInfo}`);
|
|
34
|
+
};
|
|
35
|
+
const createSourceEntry = (filename, dataname, content, contentGzip, mimeType, md5, isGzip) => ({
|
|
36
|
+
filename,
|
|
37
|
+
dataname,
|
|
38
|
+
datanameUpperCase: dataname.toUpperCase(),
|
|
39
|
+
content,
|
|
40
|
+
contentGzip: isGzip ? contentGzip : content,
|
|
41
|
+
isGzip,
|
|
42
|
+
mime: mimeType,
|
|
43
|
+
md5
|
|
44
|
+
});
|
|
45
|
+
const updateExtensionGroup = (extension) => {
|
|
46
|
+
const group = filesByExtension.find((fe) => fe.extension === extension);
|
|
47
|
+
if (group) {
|
|
48
|
+
group.count += 1;
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
filesByExtension.push({ extension, count: 1 });
|
|
52
|
+
}
|
|
53
|
+
};
|
|
22
54
|
console.log('Collecting source files');
|
|
23
55
|
const files = (0, file_1.getFiles)();
|
|
24
56
|
if (files.size === 0) {
|
|
@@ -36,42 +68,15 @@ for (const [originalFilename, content] of files) {
|
|
|
36
68
|
let extension = node_path_1.default.extname(filename).toUpperCase();
|
|
37
69
|
if (extension.startsWith('.'))
|
|
38
70
|
extension = extension.slice(1);
|
|
39
|
-
|
|
40
|
-
if (group)
|
|
41
|
-
group.count += 1;
|
|
42
|
-
else
|
|
43
|
-
filesByExtension.push({ extension, count: 1 });
|
|
71
|
+
updateExtensionGroup(extension);
|
|
44
72
|
const md5 = (0, node_crypto_1.createHash)('md5').update(content).digest('hex');
|
|
45
73
|
summary.size += content.length;
|
|
46
74
|
const zipContent = (0, node_zlib_1.gzipSync)(content, { level: 9 });
|
|
47
75
|
summary.gzipsize += zipContent.length;
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
dataname,
|
|
53
|
-
datanameUpperCase: dataname.toUpperCase(),
|
|
54
|
-
content,
|
|
55
|
-
contentGzip: zipContent,
|
|
56
|
-
isGzip: true,
|
|
57
|
-
mime: mimeType,
|
|
58
|
-
md5
|
|
59
|
-
});
|
|
60
|
-
console.log((0, consoleColor_1.greenLog)(` [${originalFilename}] ${' '.repeat(longestFilename - originalFilename.length)} ✓ gzip used (${content.length} -> ${zipContent.length} = ${zipRatio}%)`));
|
|
61
|
-
}
|
|
62
|
-
else {
|
|
63
|
-
sources.push({
|
|
64
|
-
filename,
|
|
65
|
-
dataname,
|
|
66
|
-
datanameUpperCase: dataname.toUpperCase(),
|
|
67
|
-
content,
|
|
68
|
-
contentGzip: content,
|
|
69
|
-
isGzip: false,
|
|
70
|
-
mime: mimeType,
|
|
71
|
-
md5
|
|
72
|
-
});
|
|
73
|
-
console.log((0, consoleColor_1.yellowLog)(` [${originalFilename}] ${' '.repeat(longestFilename - originalFilename.length)} x gzip unused ${content.length <= 1024 ? `(too small) ` : ''}(${content.length} -> ${zipContent.length} = ${zipRatio}%)`));
|
|
74
|
-
}
|
|
76
|
+
const useGzip = shouldUseGzip(content.length, zipContent.length);
|
|
77
|
+
sources.push(createSourceEntry(filename, dataname, content, zipContent, mimeType, md5, useGzip));
|
|
78
|
+
const padding = ' '.repeat(longestFilename - originalFilename.length);
|
|
79
|
+
console.log(formatCompressionLog(originalFilename, padding, content.length, zipContent.length, useGzip));
|
|
75
80
|
}
|
|
76
81
|
console.log('');
|
|
77
82
|
filesByExtension.sort((left, right) => left.extension.localeCompare(right.extension));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "svelteesp32",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.3",
|
|
4
4
|
"description": "Convert Svelte (or any frontend) JS application to serve it from ESP32 webserver (PsychicHttp)",
|
|
5
5
|
"author": "BCsabaEngine",
|
|
6
6
|
"license": "ISC",
|
|
@@ -31,14 +31,17 @@
|
|
|
31
31
|
"dev:async": "nodemon src/index.ts -- -e async -s ./demo/svelte/dist -o ./demo/esp32/include/svelteesp32.h --etag=true --gzip=true --cachetime=86400 --version=v$npm_package_version",
|
|
32
32
|
"dev:psychic": "nodemon src/index.ts -- -e psychic -s ./demo/svelte/dist -o ./demo/esp32/include/svelteesp32.h --etag=false --gzip=false --version=v$npm_package_version",
|
|
33
33
|
"dev:psychic2": "nodemon src/index.ts -- -e psychic2 -s ./demo/svelte/dist -o ./demo/esp32/include/svelteesp32.h --etag=false --gzip=false --version=v$npm_package_version",
|
|
34
|
-
"test:
|
|
34
|
+
"test:esp32": "./package.script && ~/.platformio/penv/bin/pio run -d ./demo/esp32",
|
|
35
|
+
"test:esp32idf": "./package.script && ~/.platformio/penv/bin/pio run -d ./demo/esp32idf",
|
|
36
|
+
"test:all": "node --run test:esp32 && node --run test:esp32idf",
|
|
35
37
|
"clean": "tsc --build --clean",
|
|
36
38
|
"build": "tsc --build --clean && tsc --build --force",
|
|
37
39
|
"format:check": "prettier --check .",
|
|
38
|
-
"format:fix": "prettier --write .",
|
|
40
|
+
"format:fix": "prettier --write . | grep -v 'unchanged' | sed G",
|
|
39
41
|
"lint:check": "eslint .",
|
|
40
42
|
"lint:fix": "eslint --fix .",
|
|
41
|
-
"fix": "
|
|
43
|
+
"fix": "node --run format:fix && node --run lint:fix && node --run format:fix",
|
|
44
|
+
"all": "node --run fix && node --run build",
|
|
42
45
|
"npm:reinstall": "rm -rf ./node_modules && rm -f ./package-lock.json && npm i && npm i"
|
|
43
46
|
},
|
|
44
47
|
"keywords": [
|
|
@@ -55,18 +58,18 @@
|
|
|
55
58
|
],
|
|
56
59
|
"devDependencies": {
|
|
57
60
|
"@types/mime-types": "^3.0.1",
|
|
58
|
-
"@types/node": "^24.
|
|
59
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
60
|
-
"@typescript-eslint/parser": "^8.
|
|
61
|
-
"eslint": "^9.
|
|
61
|
+
"@types/node": "^24.9.2",
|
|
62
|
+
"@typescript-eslint/eslint-plugin": "^8.46.2",
|
|
63
|
+
"@typescript-eslint/parser": "^8.46.2",
|
|
64
|
+
"eslint": "^9.39.0",
|
|
62
65
|
"eslint-config-prettier": "^10.1.8",
|
|
63
66
|
"eslint-plugin-simple-import-sort": "^12.1.1",
|
|
64
|
-
"eslint-plugin-unicorn": "^
|
|
67
|
+
"eslint-plugin-unicorn": "^62.0.0",
|
|
65
68
|
"nodemon": "^3.1.10",
|
|
66
69
|
"prettier": "^3.6.2",
|
|
67
70
|
"ts-node": "^10.9.2",
|
|
68
|
-
"tsx": "^4.20.
|
|
69
|
-
"typescript": "^5.9.
|
|
71
|
+
"tsx": "^4.20.6",
|
|
72
|
+
"typescript": "^5.9.3"
|
|
70
73
|
},
|
|
71
74
|
"dependencies": {
|
|
72
75
|
"glob": "^11.0.3",
|