svelteesp32 1.2.7 → 1.3.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 +38 -0
- package/dist/commandLine.d.ts +1 -0
- package/dist/commandLine.js +5 -0
- package/dist/cppCode.d.ts +1 -1
- package/dist/cppCode.js +27 -30
- package/dist/index.js +8 -7
- package/package.json +13 -9
package/README.md
CHANGED
|
@@ -14,6 +14,8 @@ This npm package provides a solution for **inserting any JS client application i
|
|
|
14
14
|
|
|
15
15
|
> Starting with version v1.2.0, ESP8266/ESP8285 is also supported.
|
|
16
16
|
|
|
17
|
+
> Starting with version v1.3.0, c++ defines can be used.
|
|
18
|
+
|
|
17
19
|
### Usage
|
|
18
20
|
|
|
19
21
|
**Install package** as devDependency (it is practical if the package is part of the project so that you always receive updates)
|
|
@@ -98,9 +100,16 @@ void setup()
|
|
|
98
100
|
}
|
|
99
101
|
```
|
|
100
102
|
|
|
103
|
+
You can find a minimal buildable example platformio project in [demo/esp32](demo/esp32) folder.
|
|
104
|
+
|
|
101
105
|
The content of **generated file** (do not edit, just use)
|
|
102
106
|
|
|
103
107
|
```c
|
|
108
|
+
#define SVELTEESP32_COUNT 5
|
|
109
|
+
#define SVELTEESP32_SIZE 145633
|
|
110
|
+
#define SVELTEESP32_FILE_index_html
|
|
111
|
+
...
|
|
112
|
+
|
|
104
113
|
const uint8_t data0[12547] = {0x1f, 0x8b, 0x8, 0x0, ...
|
|
105
114
|
const uint8_t data1[5368] = {0x1f, 0x8b, 0x8, 0x0, 0x0, ...
|
|
106
115
|
const char * etag0 = "387b88e345cc56ef9091...";
|
|
@@ -164,6 +173,34 @@ The use of ETag is **not enabled by default**, this can be achieved with the `--
|
|
|
164
173
|
|
|
165
174
|
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.
|
|
166
175
|
|
|
176
|
+
### C++ defines
|
|
177
|
+
|
|
178
|
+
To make it easy to integrate into a larger c++ project, we have made a couple of variables available as c++ defines.
|
|
179
|
+
|
|
180
|
+
You can use the COUNT and SIZE constants:
|
|
181
|
+
|
|
182
|
+
```c
|
|
183
|
+
...
|
|
184
|
+
#include "svelteesp32.h"
|
|
185
|
+
|
|
186
|
+
#if SVELTEESP32_COUNT != 5
|
|
187
|
+
#error Invalid file count
|
|
188
|
+
#endif
|
|
189
|
+
...
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
You can include a warning if a named file accidentally missing from the build:
|
|
193
|
+
|
|
194
|
+
```c
|
|
195
|
+
...
|
|
196
|
+
#include "svelteesp32.h"
|
|
197
|
+
|
|
198
|
+
#ifndef SVELTEESP32_FILE_index_html
|
|
199
|
+
#error Missing index file
|
|
200
|
+
#endif
|
|
201
|
+
...
|
|
202
|
+
```
|
|
203
|
+
|
|
167
204
|
### Command line options
|
|
168
205
|
|
|
169
206
|
| Option | Required | Description | default |
|
|
@@ -174,6 +211,7 @@ Typically, the entry point for web applications is the **index.htm or index.html
|
|
|
174
211
|
| `--etag` | | Use ETag header for cache | false |
|
|
175
212
|
| `--no-gzip` | | Do not compress content with gzip | false -> gzip used |
|
|
176
213
|
| `--espmethod` | x | Name of generated method | `initSvelteStaticFiles` |
|
|
214
|
+
| `--define` | x | Prefix of c++ defines | `SVELTEESP32` |
|
|
177
215
|
| `-h` | | Show help | |
|
|
178
216
|
|
|
179
217
|
### Q&A
|
package/dist/commandLine.d.ts
CHANGED
package/dist/commandLine.js
CHANGED
|
@@ -42,6 +42,11 @@ exports.cmdLine = (0, ts_command_line_args_1.parse)({
|
|
|
42
42
|
description: 'Name of generated method',
|
|
43
43
|
defaultValue: 'initSvelteStaticFiles'
|
|
44
44
|
},
|
|
45
|
+
define: {
|
|
46
|
+
type: String,
|
|
47
|
+
description: 'Prefix of c++ defines',
|
|
48
|
+
defaultValue: 'SVELTEESP32'
|
|
49
|
+
},
|
|
45
50
|
help: { type: Boolean, optional: true, alias: 'h', description: 'Shows this help' }
|
|
46
51
|
}, {
|
|
47
52
|
helpArg: 'help',
|
package/dist/cppCode.d.ts
CHANGED
package/dist/cppCode.js
CHANGED
|
@@ -14,17 +14,16 @@ const psychicTemplate = `
|
|
|
14
14
|
#include <PsychicHttp.h>
|
|
15
15
|
#include <PsychicHttpsServer.h>
|
|
16
16
|
|
|
17
|
+
#define {{definePrefix}}_COUNT {{fileCount}}
|
|
18
|
+
#define {{definePrefix}}_SIZE {{fileSize}}
|
|
17
19
|
{{#each sources}}
|
|
18
|
-
{{
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
{{
|
|
23
|
-
{{else}}
|
|
24
|
-
const uint8_t data{{this.index}}[{{this.length}}] = { {{this.bytes}} };
|
|
20
|
+
#define {{../definePrefix}}_FILE_{{this.dataname}}
|
|
21
|
+
{{/each}}
|
|
22
|
+
|
|
23
|
+
{{#each sources}}
|
|
24
|
+
const uint8_t data_{{this.dataname}}[{{this.length}}] = { {{this.bytes}} };
|
|
25
25
|
{{#if ../isEtag}}
|
|
26
|
-
const char *
|
|
27
|
-
{{/if}}
|
|
26
|
+
const char * etag_{{this.dataname}} = "{{this.md5}}";
|
|
28
27
|
{{/if}}
|
|
29
28
|
{{/each}}
|
|
30
29
|
|
|
@@ -32,7 +31,7 @@ void {{methodName}}(PsychicHttpServer * server) {
|
|
|
32
31
|
{{#each sources}}
|
|
33
32
|
{{#if this.isDefault}}server->defaultEndpoint = {{/if}}server->on("/{{this.filename}}", HTTP_GET, [](PsychicRequest * request) {
|
|
34
33
|
{{#if ../isEtag}}
|
|
35
|
-
if (request->hasHeader("If-None-Match") && request->header("If-None-Match") == String({{
|
|
34
|
+
if (request->hasHeader("If-None-Match") && request->header("If-None-Match") == String(etag_{{this.dataname}})) {
|
|
36
35
|
PsychicResponse response304(request);
|
|
37
36
|
response304.setCode(304);
|
|
38
37
|
return response304.send();
|
|
@@ -44,9 +43,9 @@ void {{methodName}}(PsychicHttpServer * server) {
|
|
|
44
43
|
response.addHeader("Content-Encoding", "gzip");
|
|
45
44
|
{{/if}}
|
|
46
45
|
{{#if ../isEtag}}
|
|
47
|
-
response.addHeader("ETag", {{
|
|
46
|
+
response.addHeader("ETag", etag_{{this.dataname}});
|
|
48
47
|
{{/if}}
|
|
49
|
-
response.setContent({{
|
|
48
|
+
response.setContent(data_{{this.dataname}}, sizeof(data_{{this.dataname}}));
|
|
50
49
|
return response.send();
|
|
51
50
|
});
|
|
52
51
|
|
|
@@ -62,43 +61,40 @@ const asyncTemplate = `
|
|
|
62
61
|
#include <Arduino.h>
|
|
63
62
|
#include <ESPAsyncWebServer.h>
|
|
64
63
|
|
|
64
|
+
#define {{definePrefix}}_COUNT {{fileCount}}
|
|
65
|
+
#define {{definePrefix}}_SIZE {{fileSize}}
|
|
65
66
|
{{#each sources}}
|
|
66
|
-
{{
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
{{
|
|
71
|
-
{{else}}
|
|
72
|
-
const uint8_t data{{this.index}}[{{this.length}}] PROGMEM = { {{this.bytes}} };
|
|
67
|
+
#define {{../definePrefix}}_FILE_{{this.dataname}}
|
|
68
|
+
{{/each}}
|
|
69
|
+
|
|
70
|
+
{{#each sources}}
|
|
71
|
+
const uint8_t data_{{this.dataname}}[{{this.length}}] PROGMEM = { {{this.bytes}} };
|
|
73
72
|
{{#if ../isEtag}}
|
|
74
|
-
const char *
|
|
75
|
-
{{/if}}
|
|
73
|
+
const char * etag_{{this.dataname}} = "{{this.md5}}";
|
|
76
74
|
{{/if}}
|
|
77
75
|
{{/each}}
|
|
78
76
|
|
|
79
77
|
void {{methodName}}(AsyncWebServer * server) {
|
|
80
78
|
{{#each sources}}
|
|
81
|
-
ArRequestHandlerFunction {{
|
|
79
|
+
ArRequestHandlerFunction func_{{this.dataname}} = [](AsyncWebServerRequest * request) {
|
|
82
80
|
{{#if ../isEtag}}
|
|
83
|
-
if (request->hasHeader("If-None-Match") && request->getHeader("If-None-Match")->value() == String({{
|
|
81
|
+
if (request->hasHeader("If-None-Match") && request->getHeader("If-None-Match")->value() == String(etag_{{this.dataname}})) {
|
|
84
82
|
request->send(304);
|
|
85
83
|
return;
|
|
86
84
|
}
|
|
87
85
|
{{/if}}
|
|
88
|
-
AsyncWebServerResponse *response = request->beginResponse_P(200, "{{this.mime}}", {{
|
|
86
|
+
AsyncWebServerResponse *response = request->beginResponse_P(200, "{{this.mime}}", data_{{this.dataname}}, {{this.length}});
|
|
89
87
|
{{#if this.isGzip}}
|
|
90
88
|
response->addHeader("Content-Encoding", "gzip");
|
|
91
89
|
{{/if}}
|
|
92
90
|
{{#if ../isEtag}}
|
|
93
|
-
response->addHeader("ETag", {{
|
|
91
|
+
response->addHeader("ETag", etag_{{this.dataname}});
|
|
94
92
|
{{/if}}
|
|
95
93
|
request->send(response);
|
|
96
94
|
};
|
|
95
|
+
server->on("/{{this.filename}}", HTTP_GET, func_{{this.dataname}});
|
|
97
96
|
{{#if this.isDefault}}
|
|
98
|
-
server->on("/{{this.
|
|
99
|
-
server->on("/", HTTP_GET, funcDefaultDocument);
|
|
100
|
-
{{else}}
|
|
101
|
-
server->on("/{{this.filename}}", HTTP_GET, func{{this.index}});
|
|
97
|
+
server->on("/", HTTP_GET, func_{{this.dataname}});
|
|
102
98
|
{{/if}}
|
|
103
99
|
|
|
104
100
|
{{/each}}
|
|
@@ -115,6 +111,7 @@ const getCppCode = (sources) => (0, handlebars_1.compile)(commandLine_1.cmdLine.
|
|
|
115
111
|
isDefault: s.filename.startsWith('index.htm')
|
|
116
112
|
})),
|
|
117
113
|
isEtag: commandLine_1.cmdLine.etag,
|
|
118
|
-
methodName: commandLine_1.cmdLine.espmethod
|
|
114
|
+
methodName: commandLine_1.cmdLine.espmethod,
|
|
115
|
+
definePrefix: commandLine_1.cmdLine.define
|
|
119
116
|
}).trim();
|
|
120
117
|
exports.getCppCode = getCppCode;
|
package/dist/index.js
CHANGED
|
@@ -17,7 +17,6 @@ const summary = {
|
|
|
17
17
|
gzipsize: 0
|
|
18
18
|
};
|
|
19
19
|
const sources = [];
|
|
20
|
-
let sourceIndex = 0;
|
|
21
20
|
const files = (0, file_1.getFiles)();
|
|
22
21
|
if (files.length === 0) {
|
|
23
22
|
console.error(`Directory ${commandLine_1.cmdLine.sourcepath} is empty`);
|
|
@@ -27,13 +26,15 @@ for (const file of files) {
|
|
|
27
26
|
const mime = (0, mime_types_1.lookup)(file) || 'text/plain';
|
|
28
27
|
summary.filecount++;
|
|
29
28
|
console.log(`[${file}]`);
|
|
29
|
+
const filename = file.replace(/\\/g, '/');
|
|
30
|
+
const dataname = filename.replace(/[./-]/g, '_');
|
|
30
31
|
const rawContent = (0, node_fs_1.readFileSync)(node_path_1.default.join(commandLine_1.cmdLine.sourcepath, file), { flag: 'r' });
|
|
31
32
|
const md5 = (0, node_crypto_1.createHash)('md5').update(rawContent).digest('hex');
|
|
32
33
|
summary.size += rawContent.length;
|
|
33
34
|
if (commandLine_1.cmdLine['no-gzip']) {
|
|
34
35
|
sources.push({
|
|
35
|
-
|
|
36
|
-
|
|
36
|
+
filename: filename,
|
|
37
|
+
dataname,
|
|
37
38
|
content: rawContent,
|
|
38
39
|
isGzip: false,
|
|
39
40
|
mime,
|
|
@@ -46,8 +47,8 @@ for (const file of files) {
|
|
|
46
47
|
summary.gzipsize += zipContent.length;
|
|
47
48
|
if (rawContent.length > 100 && zipContent.length < rawContent.length * 0.85) {
|
|
48
49
|
sources.push({
|
|
49
|
-
|
|
50
|
-
|
|
50
|
+
filename: filename,
|
|
51
|
+
dataname,
|
|
51
52
|
content: zipContent,
|
|
52
53
|
isGzip: true,
|
|
53
54
|
mime,
|
|
@@ -57,8 +58,8 @@ for (const file of files) {
|
|
|
57
58
|
}
|
|
58
59
|
else {
|
|
59
60
|
sources.push({
|
|
60
|
-
|
|
61
|
-
|
|
61
|
+
filename: filename,
|
|
62
|
+
dataname,
|
|
62
63
|
content: rawContent,
|
|
63
64
|
isGzip: false,
|
|
64
65
|
mime,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "svelteesp32",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
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",
|
|
@@ -28,10 +28,13 @@
|
|
|
28
28
|
},
|
|
29
29
|
"homepage": "https://github.com/BCsabaEngine/svelteesp32",
|
|
30
30
|
"scripts": {
|
|
31
|
-
"dev:
|
|
32
|
-
"dev:psychic
|
|
33
|
-
"
|
|
34
|
-
"
|
|
31
|
+
"dev:async": "nodemon src/index.ts -- -e async -s ./demo/svelte/dist -o ./demo/esp32/include/svelteesp32async.h --etag",
|
|
32
|
+
"dev:psychic": "nodemon src/index.ts -- -e psychic -s ./demo/svelte/dist -o ./demo/esp32/include/svelteesp32psychic.h --etag",
|
|
33
|
+
"run:async": "tsx src/index.ts -e async -s ./demo/svelte/dist -o ./demo/esp32/include/svelteesp32async.h --etag",
|
|
34
|
+
"run:psychic": "tsx src/index.ts -e psychic -s ./demo/svelte/dist -o ./demo/esp32/include/svelteesp32psychic.h --etag",
|
|
35
|
+
"run:both": "npm run run:async && npm run run:psychic",
|
|
36
|
+
"platformio": "~/.platformio/penv/bin/pio run -d ./demo/esp32",
|
|
37
|
+
"run:both:build": "npm run run:both && npm run platformio",
|
|
35
38
|
"clean": "tsc --build --clean",
|
|
36
39
|
"build": "tsc --build --clean && tsc --build --force",
|
|
37
40
|
"format:check": "prettier --check .",
|
|
@@ -53,16 +56,17 @@
|
|
|
53
56
|
],
|
|
54
57
|
"devDependencies": {
|
|
55
58
|
"@types/mime-types": "^2.1.4",
|
|
56
|
-
"@types/node": "^
|
|
57
|
-
"@typescript-eslint/eslint-plugin": "^
|
|
58
|
-
"@typescript-eslint/parser": "^
|
|
59
|
-
"eslint": "^
|
|
59
|
+
"@types/node": "^22.2.0",
|
|
60
|
+
"@typescript-eslint/eslint-plugin": "^8.1.0",
|
|
61
|
+
"@typescript-eslint/parser": "^8.1.0",
|
|
62
|
+
"eslint": "^9.9.0",
|
|
60
63
|
"eslint-config-prettier": "^9.1.0",
|
|
61
64
|
"eslint-plugin-simple-import-sort": "^12.1.1",
|
|
62
65
|
"eslint-plugin-unicorn": "^55.0.0",
|
|
63
66
|
"nodemon": "^3.1.4",
|
|
64
67
|
"prettier": "^3.3.3",
|
|
65
68
|
"ts-node": "^10.9.2",
|
|
69
|
+
"tsx": "^4.17.0",
|
|
66
70
|
"typescript": "^5.5.4"
|
|
67
71
|
},
|
|
68
72
|
"dependencies": {
|