svelteesp32 1.0.3 → 1.0.4

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,31 +1,52 @@
1
- # [svelteesp32] Convert Svelte (or any frontend) JS application to serve it from ESP32 webserver (PsychicHttp)
1
+ # `svelteesp32` ![image](https://badges.github.io/stability-badges/dist/stable.svg)
2
+
3
+ # Convert Svelte (or React/Angular/Vue) JS application to serve it from ESP32 webserver
2
4
 
3
5
  ### Forget SPIFFS and LittleFS now
4
6
 
5
- I often make small to medium-sized microcontroller solutions that run on ESP32. If a web interface is needed, I will create a Svelte application. The Svelte application is practically served by the ESP32.
7
+ I often make small to medium-sized microcontroller solutions that run on ESP32. If a web interface is needed, I create a Svelte application. The Svelte application is practically served by the ESP32.
6
8
 
7
- 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 Svelte files are included inline in the Arduino/PlatformIO code.
9
+ 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.
8
10
 
9
- This npm package provides a solution for **inserting any JS client application into the ESP32 web server** (PsychicHttp is my favorite, faster than ESPAsyncWebServer). For this, JS, html, css, font, etc. files must be converted to binary. npm is easy to use and easy to **integrate into your CI/CD pipeline**.
11
+ This npm package provides a solution for **inserting any JS client application into the ESP32 web server** (PsychicHttp is my favorite, faster than ESPAsyncWebServer). 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**.
10
12
 
11
13
  ### Usage
12
14
 
13
- Install package as devDependency (it is practical if the package is part of the project so that you always receive updates)
15
+ **Install package** as devDependency (it is practical if the package is part of the project so that you always receive updates)
14
16
 
15
17
  ```bash
16
18
  npm install -D svelteesp32
17
19
  ```
18
20
 
19
- After a successful Svelte build create az includeable cpp file
21
+ After a successful Svelte build (rollup/webpack/vite) **create an includeable c++ header** file
20
22
 
21
23
  ```bash
22
24
  npx svelteesp32 -s ../svelteapp/dist -o ../esp32project/svelteesp32.h
25
+ ```
26
+
27
+ During the **translation process**, the processed file details are visible, and at the end, the result shows the ESP32's memory allocation (gzip size)
28
+
29
+ ```
30
+ [assets/index-KwubEIf-.js]
31
+ ✓ gzip used (38850 -> 12547)
32
+
33
+ [assets/index-Soe6cpLA.css]
34
+ ✓ gzip used (32494 -> 5368)
23
35
 
24
- // compress files and serve as gzip
25
- npx svelteesp32 -s ../svelteapp/dist -o ../esp32project/svelteesp32.h -g
36
+ [favicon.png]
37
+ x gzip unused (33249 -> 33282)
38
+
39
+ [index.html]
40
+ ✓ gzip used (472 -> 308)
41
+
42
+ [roboto_regular.json]
43
+ ✓ gzip used (363757 -> 93567)
44
+
45
+ 5 files, 458kB original size, 142kB gzip size
46
+ ../../../Arduino/EspSvelte/svelteesp32.h 842kB size
26
47
  ```
27
48
 
28
- Include svelteesp32.h into yout Arduino cpp project (copy it next to the ino file)
49
+ **Include svelteesp32.h** into your Arduino or PlatformIO c++ project (copy it next to the main c++ file)
29
50
 
30
51
  ```c
31
52
  ...
@@ -47,32 +68,65 @@ void setup()
47
68
  }
48
69
  ```
49
70
 
50
- The content of generated file (do not edit, just use)
71
+ The content of **generated file** (do not edit, just use)
51
72
 
52
73
  ```c
74
+ const uint8_t data0[12547] = {0x1f, 0x8b, 0x8, 0x0, ...
75
+ const uint8_t data1[5368] = {0x1f, 0x8b, 0x8, 0x0, 0x0, ...
76
+
53
77
  void initSvelteStaticFiles(PsychicHttpServer * server) {
54
- server->on("assets/index-KwubEIf-.js", HTTP_GET, [](PsychicRequest * request)
55
- {
56
- const uint8_t data[] = {0x1f, 0x8b, 0x8, 0x0, 0x0, ...}
57
-
58
- PsychicStreamResponse response(request, "application/javascript");
59
- response.addHeader("Content-Encoding", "gzip");
60
- response.beginSend();
61
- for (int i = 0; i < sizeof(data); i++) response.write(data[i]);
62
- return response.endSend();
63
- });
64
-
65
- server->on("assets/index-Soe6cpLA.css", HTTP_GET, [](PsychicRequest * request)
66
- {
67
- const uint8_t data[] = {0x1f, 0x8b, 0x8, 0x0, 0x0, ...}
68
-
69
- PsychicStreamResponse response(request, "text/css");
70
- response.addHeader("Content-Encoding", "gzip");
71
- response.beginSend();
72
- for (int i = 0; i < sizeof(data); i++) response.write(data[i]);
73
- return response.endSend();
74
- });
78
+ server->on("/assets/index-KwubEIf-.js", HTTP_GET, [](PsychicRequest * request)
79
+ {
80
+ PsychicResponse response(request);
81
+ response.setContentType("application/javascript");
82
+ response.addHeader("Content-Encoding", "gzip");
83
+ response.setContent(data0, sizeof(data0));
84
+ return response.send();
85
+ });
86
+
87
+ server->on("/assets/index-Soe6cpLA.css", HTTP_GET, [](PsychicRequest * request)
88
+ {
89
+ PsychicResponse response(request);
90
+ response.setContentType("text/css");
91
+ response.addHeader("Content-Encoding", "gzip");
92
+ response.setContent(data1, sizeof(data1));
93
+ return response.send();
94
+ });
75
95
 
76
96
  ...
77
97
  }
78
98
  ```
99
+
100
+ ### Gzip
101
+
102
+ 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 and sent to the browser.
103
+
104
+ During the translation process, data in gzip format is generated and will be used if the size is greater than 100 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 header information.
105
+
106
+ Automatic compression can be turned off with the `--no-gzip` option.
107
+
108
+ ### Main entry point - index.html
109
+
110
+ 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://esp32_xxx.local` or just entering the `http://x.y.w.z/` IP address will serve this main file.
111
+
112
+ ### Command line options
113
+
114
+ | Option | Mandatory | Description | default |
115
+ | ------------- | :-------: | ---------------------------------------------- | ----------------------- |
116
+ | `-s` | x | Source dist folder contains compiled web files | |
117
+ | `-o` | x | Generated output file with path | `svelteesp32.h` |
118
+ | `--no-gzip` | | Do not compress content with gzip | |
119
+ | `--espmethod` | x | Name of generated method | `initSvelteStaticFiles` |
120
+ | `-h` | | Show help | |
121
+
122
+ ### Q&A
123
+
124
+ - **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.
125
+
126
+ - **How fast is cpp file compilation?** The cpp 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 development.
127
+
128
+ - **Does the solution use PROGMEM?** No and yes. ESP32 no longer has PROGMEM. (Exists, but does not affect the translation). Instead, if we use a const array in the global namespace, its content will be placed in the code area, i.e. it will not be used from the heap or the stack, so the content of the files to be served will be placed next to the code.
129
+
130
+ - **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.
131
+
132
+ - **Will you develop it further?** Since I use it myself, I will do my best to make the solution better and better.
@@ -1,8 +1,8 @@
1
1
  interface ICopyFilesArguments {
2
- sourcePath: string;
3
- outputFile: string;
4
- espMethodName: string;
5
- gzip: boolean;
2
+ sourcepath: string;
3
+ outputfile: string;
4
+ espmethod: string;
5
+ 'no-gzip': boolean;
6
6
  help?: boolean;
7
7
  }
8
8
  export declare const cmdLine: ICopyFilesArguments;
@@ -4,24 +4,23 @@ exports.cmdLine = void 0;
4
4
  const node_fs_1 = require("node:fs");
5
5
  const ts_command_line_args_1 = require("ts-command-line-args");
6
6
  exports.cmdLine = (0, ts_command_line_args_1.parse)({
7
- sourcePath: {
7
+ sourcepath: {
8
8
  type: String,
9
9
  alias: 's',
10
10
  description: 'Source dist folder contains compiled web files'
11
11
  },
12
- outputFile: {
12
+ outputfile: {
13
13
  type: String,
14
14
  alias: 'o',
15
15
  description: 'Generated output file with path',
16
16
  defaultValue: 'svelteesp32.h'
17
17
  },
18
- gzip: {
18
+ 'no-gzip': {
19
19
  type: Boolean,
20
- alias: 'g',
21
- description: 'Compress content with gzip',
20
+ description: 'Do not compress content with gzip',
22
21
  defaultValue: false
23
22
  },
24
- espMethodName: {
23
+ espmethod: {
25
24
  type: String,
26
25
  description: 'Name of generated method',
27
26
  defaultValue: 'initSvelteStaticFiles'
@@ -31,7 +30,7 @@ exports.cmdLine = (0, ts_command_line_args_1.parse)({
31
30
  helpArg: 'help',
32
31
  headerContentSections: [{ header: 'svelteesp32', content: 'Svelte JS to ESP32 converter' }]
33
32
  });
34
- if (!(0, node_fs_1.existsSync)(exports.cmdLine.sourcePath) || !(0, node_fs_1.statSync)(exports.cmdLine.sourcePath).isDirectory()) {
35
- console.error(`Directory ${exports.cmdLine.sourcePath} not exists or not a directory`);
33
+ if (!(0, node_fs_1.existsSync)(exports.cmdLine.sourcepath) || !(0, node_fs_1.statSync)(exports.cmdLine.sourcepath).isDirectory()) {
34
+ console.error(`Directory ${exports.cmdLine.sourcepath} not exists or not a directory`);
36
35
  process.exit(1);
37
36
  }
package/dist/cppCode.js CHANGED
@@ -43,7 +43,7 @@ const getCppCode = (sources) => {
43
43
  }
44
44
  let result = fileTemplate;
45
45
  result = replaceAll(result, '$arrays$', arrays.join('\n'));
46
- result = replaceAll(result, '$method$', commandLine_1.cmdLine.espMethodName);
46
+ result = replaceAll(result, '$method$', commandLine_1.cmdLine.espmethod);
47
47
  result = replaceAll(result, '$code$', blocks.join(''));
48
48
  return result;
49
49
  };
package/dist/file.js CHANGED
@@ -4,7 +4,7 @@ exports.getFiles = void 0;
4
4
  const node_path_1 = require("node:path");
5
5
  const glob_1 = require("glob");
6
6
  const commandLine_1 = require("./commandLine");
7
- const getFiles = () => (0, glob_1.globSync)((0, node_path_1.join)('**/*'), { cwd: commandLine_1.cmdLine.sourcePath, nodir: true })
7
+ const getFiles = () => (0, glob_1.globSync)((0, node_path_1.join)('**/*'), { cwd: commandLine_1.cmdLine.sourcepath, nodir: true })
8
8
  .filter((filename) => !['.gz', '.brottli'].includes((0, node_path_1.extname)(filename)))
9
9
  .sort();
10
10
  exports.getFiles = getFiles;
package/dist/index.js CHANGED
@@ -18,9 +18,19 @@ for (const file of (0, file_1.getFiles)()) {
18
18
  const mime = (0, mime_types_1.lookup)(file) || 'text/plain';
19
19
  summary.filecount++;
20
20
  console.log(`[${file}]`);
21
- const rawContent = (0, node_fs_1.readFileSync)((0, node_path_1.join)(commandLine_1.cmdLine.sourcePath, file), { flag: 'r' });
21
+ const rawContent = (0, node_fs_1.readFileSync)((0, node_path_1.join)(commandLine_1.cmdLine.sourcepath, file), { flag: 'r' });
22
22
  summary.size += rawContent.length;
23
- if (commandLine_1.cmdLine.gzip) {
23
+ if (commandLine_1.cmdLine['no-gzip']) {
24
+ sources.push({
25
+ index: sourceIndex++,
26
+ filename: file,
27
+ content: rawContent,
28
+ isGzip: false,
29
+ mime
30
+ });
31
+ console.log(`- gzip skipped (${rawContent.length})`);
32
+ }
33
+ else {
24
34
  const zipContent = (0, node_zlib_1.gzipSync)(rawContent, { level: 9 });
25
35
  summary.gzipsize += zipContent.length;
26
36
  if (rawContent.length > 100 && zipContent.length < rawContent.length * 0.85) {
@@ -44,22 +54,14 @@ for (const file of (0, file_1.getFiles)()) {
44
54
  console.log(`x gzip unused (${rawContent.length} -> ${zipContent.length})`);
45
55
  }
46
56
  }
47
- else {
48
- sources.push({
49
- index: sourceIndex++,
50
- filename: file,
51
- content: rawContent,
52
- isGzip: false,
53
- mime
54
- });
55
- console.log(`- gzip skipped (${rawContent.length})`);
56
- }
57
57
  console.log('');
58
58
  }
59
59
  const cppFile = (0, cppCode_1.getCppCode)(sources);
60
- (0, node_fs_1.writeFileSync)(commandLine_1.cmdLine.outputFile, cppFile);
61
- if (commandLine_1.cmdLine.gzip)
62
- console.log(`${summary.filecount} files, ${Math.round(summary.size / 1024)}kB original size, ${Math.round(summary.gzipsize / 1024)}kB gzip size`);
63
- else
60
+ (0, node_fs_1.writeFileSync)(commandLine_1.cmdLine.outputfile, cppFile);
61
+ if (commandLine_1.cmdLine['no-gzip']) {
64
62
  console.log(`${summary.filecount} files, ${Math.round(summary.size / 1024)}kB original size`);
65
- console.log(`${commandLine_1.cmdLine.outputFile} ${Math.round(cppFile.length / 1024)}kB size`);
63
+ }
64
+ else {
65
+ console.log(`${summary.filecount} files, ${Math.round(summary.size / 1024)}kB original size, ${Math.round(summary.gzipsize / 1024)}kB gzip size`);
66
+ }
67
+ console.log(`${commandLine_1.cmdLine.outputfile} ${Math.round(cppFile.length / 1024)}kB size`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svelteesp32",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
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,7 +28,7 @@
28
28
  },
29
29
  "homepage": "https://github.com/BCsabaEngine/svelteesp32",
30
30
  "scripts": {
31
- "dev": "nodemon src/index.ts -- -s ./svelte/dist -o ../../../Arduino/EspSvelte/svelteesp32.h -g",
31
+ "dev": "nodemon src/index.ts -- -s ./svelte/dist -o ../../../Arduino/EspSvelte/svelteesp32.h",
32
32
  "clean": "tsc --build --clean",
33
33
  "build": "tsc --build --clean && tsc --build --force",
34
34
  "format:check": "prettier --check .",
@@ -48,8 +48,8 @@
48
48
  "devDependencies": {
49
49
  "@types/mime-types": "^2.1.4",
50
50
  "@types/node": "^20.11.17",
51
- "@typescript-eslint/eslint-plugin": "^6.21.0",
52
- "@typescript-eslint/parser": "^6.21.0",
51
+ "@typescript-eslint/eslint-plugin": "^7.0.1",
52
+ "@typescript-eslint/parser": "^7.0.1",
53
53
  "eslint": "^8.56.0",
54
54
  "eslint-config-prettier": "^9.1.0",
55
55
  "eslint-plugin-simple-import-sort": "^12.0.0",