svelteesp32 1.0.1

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 ADDED
@@ -0,0 +1,48 @@
1
+ # [svelteesp32] Convert Svelte (or any frontend) JS application to serve it from ESP32 webserver (PsychicHttp)
2
+
3
+ ### Forget SPIFFS and LittleFS now
4
+
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.
6
+
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.
8
+
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**.
10
+
11
+ ### Usage
12
+
13
+ Install package as devDependency (it is practical if the package is part of the project so that you always receive updates)
14
+
15
+ ```
16
+ npm install -D svelteesp32
17
+ ```
18
+
19
+ After a successful Svelte build create az includeable cpp file
20
+
21
+ ```bash
22
+ npx svelteesp32 -s ../svelteapp/dist -o ../esp32project/svelteesp32.h
23
+
24
+ // compress files and serve as gzip
25
+ npx svelteesp32 -s ../svelteapp/dist -o ../esp32project/svelteesp32.h -g
26
+ ```
27
+
28
+ Include svelteesp32.h into yout Arduino cpp project (copy it next to the ino file)
29
+
30
+ ```c
31
+ ...
32
+
33
+ #include <PsychicHttp.h>
34
+ #include "svelteesp32.h"
35
+
36
+ PsychicHttpServer server;
37
+
38
+ ...
39
+
40
+ void setup()
41
+ {
42
+ ...
43
+
44
+ server.listen(80);
45
+
46
+ initSvelteStaticFiles(&server);
47
+ }
48
+ ```
@@ -0,0 +1,9 @@
1
+ interface ICopyFilesArguments {
2
+ sourcePath: string;
3
+ outputFile: string;
4
+ espMethodName: string;
5
+ gzip: boolean;
6
+ help?: boolean;
7
+ }
8
+ export declare const cmdLine: ICopyFilesArguments;
9
+ export {};
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.cmdLine = void 0;
4
+ const node_fs_1 = require("node:fs");
5
+ const ts_command_line_args_1 = require("ts-command-line-args");
6
+ exports.cmdLine = (0, ts_command_line_args_1.parse)({
7
+ sourcePath: {
8
+ type: String,
9
+ alias: 's',
10
+ description: 'Source dist folder contains compiled web files'
11
+ },
12
+ outputFile: {
13
+ type: String,
14
+ alias: 'o',
15
+ description: 'Generated output file with path',
16
+ defaultValue: 'svelteesp32.h'
17
+ },
18
+ gzip: {
19
+ type: Boolean,
20
+ alias: 'g',
21
+ description: 'Compress content with gzip',
22
+ defaultValue: false
23
+ },
24
+ espMethodName: {
25
+ type: String,
26
+ description: 'Name of generated method',
27
+ defaultValue: 'initSvelteStaticFiles'
28
+ },
29
+ help: { type: Boolean, optional: true, alias: 'h', description: 'Shows this help' }
30
+ }, {
31
+ helpArg: 'help',
32
+ headerContentSections: [{ header: 'svelteesp32', content: 'Svelte JS to ESP32 converter' }]
33
+ });
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`);
36
+ process.exit(1);
37
+ }
@@ -0,0 +1,9 @@
1
+ /// <reference types="node" />
2
+ export type cppCodeSource = {
3
+ filename: string;
4
+ mime: string;
5
+ content: Buffer;
6
+ isGzip: boolean;
7
+ };
8
+ export declare const getCppCode: (source: cppCodeSource) => string;
9
+ export declare const adoptMethodName: (content: string) => string;
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.adoptMethodName = exports.getCppCode = void 0;
4
+ const commandLine_1 = require("./commandLine");
5
+ const containerTemplate = `
6
+ void $method(PsychicHttpServer * server) {
7
+ $code
8
+ }`;
9
+ const codeTemplate = `
10
+ server->on("$filename", HTTP_GET, [](PsychicRequest * request)
11
+ {
12
+ const uint8_t data[] = {$numbers};
13
+
14
+ PsychicStreamResponse response(request, "$mime");
15
+ $encoding
16
+ response.beginSend();
17
+ for (int i = 0; i < sizeof(data); i++) response.write(data[i]);
18
+ return response.endSend();
19
+ });
20
+ `;
21
+ const getCppCode = (source) => codeTemplate
22
+ .replace('$filename', source.filename)
23
+ .replace('$mime', source.mime)
24
+ .replace('$encoding', source.isGzip ? 'response.addHeader("Content-Encoding", "gzip");' : '')
25
+ .replace('$numbers', [...source.content].map((v) => `0x${v.toString(16)}`).join(', '));
26
+ exports.getCppCode = getCppCode;
27
+ const adoptMethodName = (content) => containerTemplate.replace('$method', commandLine_1.cmdLine.espMethodName).replace('$code', content);
28
+ exports.adoptMethodName = adoptMethodName;
package/dist/file.d.ts ADDED
@@ -0,0 +1 @@
1
+ export declare const getFiles: () => string[];
package/dist/file.js ADDED
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getFiles = void 0;
4
+ const node_path_1 = require("node:path");
5
+ const glob_1 = require("glob");
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 })
8
+ .filter((filename) => !['.gz', '.brottli'].includes((0, node_path_1.extname)(filename)))
9
+ .sort();
10
+ exports.getFiles = getFiles;
@@ -0,0 +1 @@
1
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const node_fs_1 = require("node:fs");
4
+ const node_path_1 = require("node:path");
5
+ const node_zlib_1 = require("node:zlib");
6
+ const mime_types_1 = require("mime-types");
7
+ const commandLine_1 = require("./commandLine");
8
+ const cppCode_1 = require("./cppCode");
9
+ const file_1 = require("./file");
10
+ const summary = {
11
+ filecount: 0,
12
+ size: 0,
13
+ gzipsize: 0
14
+ };
15
+ const sources = [];
16
+ for (const file of (0, file_1.getFiles)()) {
17
+ const mime = (0, mime_types_1.lookup)(file) || 'text/plain';
18
+ summary.filecount++;
19
+ console.log(`[${file}]`);
20
+ const rawContent = (0, node_fs_1.readFileSync)((0, node_path_1.join)(commandLine_1.cmdLine.sourcePath, file), { flag: 'r' });
21
+ summary.size += rawContent.length;
22
+ if (commandLine_1.cmdLine.gzip) {
23
+ const zipContent = (0, node_zlib_1.gzipSync)(rawContent, { level: 9 });
24
+ summary.gzipsize += zipContent.length;
25
+ if (rawContent.length > 100 && zipContent.length < rawContent.length * 0.85) {
26
+ sources.push({ filename: file, content: zipContent, isGzip: true, mime });
27
+ console.log(`✓ gzip used (${rawContent.length} -> ${zipContent.length})`);
28
+ }
29
+ else {
30
+ sources.push({ filename: file, content: rawContent, isGzip: false, mime });
31
+ console.log(`x gzip unused (${rawContent.length} -> ${zipContent.length})`);
32
+ }
33
+ }
34
+ else {
35
+ sources.push({ filename: file, content: rawContent, isGzip: false, mime });
36
+ console.log(`- gzip skipped (${rawContent.length})`);
37
+ }
38
+ console.log('');
39
+ }
40
+ let cppFile = '';
41
+ for (const source of sources)
42
+ cppFile += (0, cppCode_1.getCppCode)(source);
43
+ cppFile = (0, cppCode_1.adoptMethodName)(cppFile);
44
+ (0, node_fs_1.writeFileSync)(commandLine_1.cmdLine.outputFile, cppFile);
45
+ if (commandLine_1.cmdLine.gzip)
46
+ console.log(`${summary.filecount} files, ${Math.round(summary.size / 1024)}kB original size, ${Math.round(summary.gzipsize / 1024)}kB gzip size`);
47
+ else
48
+ console.log(`${summary.filecount} files, ${Math.round(summary.size / 1024)}kB original size`);
49
+ console.log(`${commandLine_1.cmdLine.outputFile} ${Math.round(cppFile.length / 1024)}kB size`);
package/package.json ADDED
@@ -0,0 +1,64 @@
1
+ {
2
+ "name": "svelteesp32",
3
+ "version": "1.0.1",
4
+ "description": "Convert Svelte (or any frontend) JS application to serve it from ESP32 webserver (PsychicHttp)",
5
+ "author": "BCsabaEngine",
6
+ "license": "ISC",
7
+ "exports": "./dist/index.js",
8
+ "main": "./dist/index.js",
9
+ "types": "./dist/index.d.ts",
10
+ "engines": {
11
+ "node": ">=18",
12
+ "npm": ">=9"
13
+ },
14
+ "files": [
15
+ "dist/**/*.js",
16
+ "dist/**/*.d.ts"
17
+ ],
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "git+https://github.com/BCsabaEngine/svelteesp32.git"
21
+ },
22
+ "bugs": {
23
+ "url": "https://github.com/BCsabaEngine/svelteesp32/issues"
24
+ },
25
+ "homepage": "https://github.com/BCsabaEngine/svelteesp32",
26
+ "scripts": {
27
+ "dev": "nodemon src/index.ts -- -s ./svelte/dist -o ./esp32.h -g",
28
+ "clean": "tsc --build --clean",
29
+ "build": "tsc --build --clean && tsc --build --force",
30
+ "format:check": "prettier --check .",
31
+ "format:fix": "prettier --write .",
32
+ "lint:check": "eslint .",
33
+ "lint:fix": "eslint --fix .",
34
+ "fix": "npm run format:fix && npm run lint:fix",
35
+ "npm-publish-patch": "npm run build && npm version patch && npm publish && npm run clean && git push",
36
+ "npm-publish-minor": "npm run build && npm version minor && npm publish && npm run clean && git push"
37
+ },
38
+ "keywords": [
39
+ "Svelte",
40
+ "eps32",
41
+ "webserver",
42
+ "PsychicHttp"
43
+ ],
44
+ "devDependencies": {
45
+ "@types/mime-types": "^2.1.4",
46
+ "@types/node": "^20.11.17",
47
+ "@typescript-eslint/eslint-plugin": "^6.21.0",
48
+ "@typescript-eslint/parser": "^6.21.0",
49
+ "eslint": "^8.56.0",
50
+ "eslint-config-prettier": "^9.1.0",
51
+ "eslint-plugin-simple-import-sort": "^12.0.0",
52
+ "eslint-plugin-sonarjs": "^0.24.0",
53
+ "eslint-plugin-unicorn": "^51.0.1",
54
+ "nodemon": "^3.0.3",
55
+ "prettier": "^3.2.5",
56
+ "ts-node": "^10.9.2",
57
+ "typescript": "^5.3.3"
58
+ },
59
+ "dependencies": {
60
+ "glob": "^10.3.10",
61
+ "mime-types": "^2.1.35",
62
+ "ts-command-line-args": "^2.5.1"
63
+ }
64
+ }