svelteesp32 2.3.3 → 2.4.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 +93 -27
- package/dist/commandLine.d.ts +4 -0
- package/dist/commandLine.js +27 -3
- package/dist/index.d.ts +8 -1
- package/dist/index.js +69 -1
- package/package.json +11 -11
package/README.md
CHANGED
|
@@ -88,6 +88,10 @@ void setup() {
|
|
|
88
88
|
|
|
89
89
|
## What's New
|
|
90
90
|
|
|
91
|
+
- **v2.4.0** — `--analyze` for CI size budget checks (per-file table, exits 1 on over-budget); `--manifest` to write a companion JSON manifest alongside the header
|
|
92
|
+
- **v2.3.3** — TypeScript 6 upgrade; `module`/`moduleResolution` updated to `Node16`, target raised to `ES2023`
|
|
93
|
+
- **v2.3.2** — Security hardening: symlink traversal blocked, RC file CWD warning, absolute `outputfile` rejected in RC files, per-file 50 MB size limit
|
|
94
|
+
- **v2.3.1** — Fixes: `--version` and `--basepath` input validation, `formatConfiguration` newline safety
|
|
91
95
|
- **v2.3.0** — `--cachetime-html` and `--cachetime-assets` for per-type cache control (e.g. `no-cache` for HTML, 1-year for content-hashed JS/CSS)
|
|
92
96
|
- **v2.2.0** — SPA routing catch-all (`--spa`) for client-side routers on all four engines
|
|
93
97
|
- **v2.1.0** — New Arduino WebServer engine (`-e webserver`), dependency updates
|
|
@@ -241,10 +245,10 @@ The generated header file includes everything your ESP needs:
|
|
|
241
245
|
#include <PsychicHttp.h>
|
|
242
246
|
#include <PsychicHttpsServer.h>
|
|
243
247
|
|
|
244
|
-
const uint8_t datagzip_assets_index_KwubEIf__js[12547] = {0x1f, 0x8b, 0x8, 0x0, ...
|
|
245
|
-
const uint8_t datagzip_assets_index_Soe6cpLA_css[5368] = {0x1f, 0x8b, 0x8, 0x0, 0x0, ...
|
|
246
|
-
const char
|
|
247
|
-
const char
|
|
248
|
+
static const uint8_t datagzip_assets_index_KwubEIf__js[12547] = {0x1f, 0x8b, 0x8, 0x0, ...
|
|
249
|
+
static const uint8_t datagzip_assets_index_Soe6cpLA_css[5368] = {0x1f, 0x8b, 0x8, 0x0, 0x0, ...
|
|
250
|
+
static const char etag_assets_index_KwubEIf__js[] = "387b88e345cc56ef9091...";
|
|
251
|
+
static const char etag_assets_index_Soe6cpLA_css[] = "d4f23bc45ef67890ab12...";
|
|
248
252
|
|
|
249
253
|
// File manifest for runtime introspection
|
|
250
254
|
struct SVELTEESP32_FileInfo {
|
|
@@ -424,6 +428,63 @@ What gets generated per engine:
|
|
|
424
428
|
|
|
425
429
|
**Note:** `--spa` requires `index.html` or `index.htm` in the source directory — a warning is printed if it is missing.
|
|
426
430
|
|
|
431
|
+
### Analyze Mode (CI Size Budget Checks)
|
|
432
|
+
|
|
433
|
+
Use `--analyze` in CI to validate firmware size budgets without producing any output file:
|
|
434
|
+
|
|
435
|
+
```bash
|
|
436
|
+
npx svelteesp32 -e psychic -s ./dist --maxsize=400k --maxgzipsize=150k --analyze
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
Sample output:
|
|
440
|
+
|
|
441
|
+
```
|
|
442
|
+
index.html Original Gzip
|
|
443
|
+
──────────────────────────────────── ──────── ────────
|
|
444
|
+
assets/index-KwubEIf-.js 37.9kB 12.3kB
|
|
445
|
+
assets/index-Soe6cpLA.css 31.7kB 5.2kB
|
|
446
|
+
favicon.png 32.5kB 32.5kB [no gzip]
|
|
447
|
+
index.html 0.5kB 0.3kB
|
|
448
|
+
────────────────────────────────────────────────────────
|
|
449
|
+
Total 102.6kB 50.3kB
|
|
450
|
+
Budget (maxsize) 400.0kB - ✓ PASS
|
|
451
|
+
Budget (maxgzipsize) - 150.0kB ✓ PASS
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
Exits with code **1** if any budget is exceeded — CI fails automatically. Mutually exclusive with `--dryrun`.
|
|
455
|
+
|
|
456
|
+
### JSON Manifest
|
|
457
|
+
|
|
458
|
+
Add `--manifest` to write a companion `.manifest.json` file alongside the header (same directory, same base name):
|
|
459
|
+
|
|
460
|
+
```bash
|
|
461
|
+
npx svelteesp32 -e psychic -s ./dist -o ./esp32/svelteesp32.h --manifest
|
|
462
|
+
# also writes ./esp32/svelteesp32.manifest.json
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
The manifest records build metadata and per-file details for tooling and dashboards:
|
|
466
|
+
|
|
467
|
+
```json
|
|
468
|
+
{
|
|
469
|
+
"generated": "2026-04-26T12:00:00.000Z",
|
|
470
|
+
"engine": "psychic",
|
|
471
|
+
"etag": "false",
|
|
472
|
+
"gzip": "true",
|
|
473
|
+
"filecount": 4,
|
|
474
|
+
"size": 104960,
|
|
475
|
+
"gzipSize": 51507,
|
|
476
|
+
"files": [
|
|
477
|
+
{
|
|
478
|
+
"path": "/assets/index-KwubEIf-.js",
|
|
479
|
+
"mime": "text/javascript",
|
|
480
|
+
"size": 38850,
|
|
481
|
+
"gzipSize": 12547,
|
|
482
|
+
"isGzip": true
|
|
483
|
+
}
|
|
484
|
+
]
|
|
485
|
+
}
|
|
486
|
+
```
|
|
487
|
+
|
|
427
488
|
### C++ Build-Time Validation
|
|
428
489
|
|
|
429
490
|
Catch configuration issues at compile time with generated defines:
|
|
@@ -473,28 +534,31 @@ Called for every response (200 = content served, 304 = cache hit).
|
|
|
473
534
|
|
|
474
535
|
## CLI Reference
|
|
475
536
|
|
|
476
|
-
| Option | Description
|
|
477
|
-
| -------------------- |
|
|
478
|
-
| `-s` | Source folder with compiled web files
|
|
479
|
-
| `-e` | Web server engine (psychic/async/espidf/webserver)
|
|
480
|
-
| `-o` | Output header file path
|
|
481
|
-
| `--etag` | ETag caching (true/false/compiler)
|
|
482
|
-
| `--gzip` | Gzip compression (true/false/compiler)
|
|
483
|
-
| `--
|
|
484
|
-
| `--
|
|
485
|
-
| `--
|
|
486
|
-
| `--
|
|
487
|
-
| `--
|
|
488
|
-
| `--cachetime
|
|
489
|
-
| `--cachetime-
|
|
490
|
-
| `--
|
|
491
|
-
| `--
|
|
492
|
-
| `--
|
|
493
|
-
| `--
|
|
494
|
-
| `--
|
|
495
|
-
| `--
|
|
496
|
-
| `--
|
|
497
|
-
|
|
|
537
|
+
| Option | Description | Default |
|
|
538
|
+
| -------------------- | -------------------------------------------------------------------------------------- | ----------------------- |
|
|
539
|
+
| `-s` | Source folder with compiled web files | (required) |
|
|
540
|
+
| `-e` | Web server engine (psychic/async/espidf/webserver) | `psychic` |
|
|
541
|
+
| `-o` | Output header file path | `svelteesp32.h` |
|
|
542
|
+
| `--etag` | ETag caching (true/false/compiler) | `false` |
|
|
543
|
+
| `--gzip` | Gzip compression (true/false/compiler) | `true` |
|
|
544
|
+
| `--created` | Include creation timestamp in header | `false` |
|
|
545
|
+
| `--exclude` | Exclude files by glob pattern | (none) |
|
|
546
|
+
| `--basepath` | URL prefix for all routes | (none) |
|
|
547
|
+
| `--maxsize` | Max total uncompressed size (e.g., `400k`, `1m`) | (none) |
|
|
548
|
+
| `--maxgzipsize` | Max total gzip size (e.g., `150k`, `500k`) | (none) |
|
|
549
|
+
| `--cachetime` | Cache-Control max-age in seconds (all files) | `0` |
|
|
550
|
+
| `--cachetime-html` | max-age for HTML files (overrides `--cachetime`) | (unset) |
|
|
551
|
+
| `--cachetime-assets` | max-age for non-HTML files (overrides `--cachetime`) | (unset) |
|
|
552
|
+
| `--version` | Version string in header | (none) |
|
|
553
|
+
| `--define` | C++ define prefix | `SVELTEESP32` |
|
|
554
|
+
| `--espmethod` | Init function name | `initSvelteStaticFiles` |
|
|
555
|
+
| `--config` | Custom RC file path | `.svelteesp32rc.json` |
|
|
556
|
+
| `--dryrun` | Show route table + summary without writing output | `false` |
|
|
557
|
+
| `--analyze` | Print per-file size table and budget status, no output written; exits 1 if over budget | `false` |
|
|
558
|
+
| `--manifest` | Write companion `.manifest.json` alongside the header | `false` |
|
|
559
|
+
| `--spa` | Serve index.html for unmatched routes (SPA routing) | `false` |
|
|
560
|
+
| `--noindexcheck` | Skip index.html validation | `false` |
|
|
561
|
+
| `-h` | Show help | |
|
|
498
562
|
|
|
499
563
|
---
|
|
500
564
|
|
|
@@ -518,7 +582,9 @@ Store your settings in `.svelteesp32rc.json` for zero-argument builds:
|
|
|
518
582
|
"cachetimeassets": 31536000,
|
|
519
583
|
"noindexcheck": false,
|
|
520
584
|
"dryrun": false,
|
|
521
|
-
"
|
|
585
|
+
"analyze": false,
|
|
586
|
+
"spa": false,
|
|
587
|
+
"manifest": false
|
|
522
588
|
}
|
|
523
589
|
```
|
|
524
590
|
|
package/dist/commandLine.d.ts
CHANGED
|
@@ -17,7 +17,9 @@ interface ICopyFilesArguments {
|
|
|
17
17
|
maxGzipSize?: number;
|
|
18
18
|
noIndexCheck?: boolean;
|
|
19
19
|
dryRun?: boolean;
|
|
20
|
+
analyze?: boolean;
|
|
20
21
|
spa?: boolean;
|
|
22
|
+
manifest?: boolean;
|
|
21
23
|
help?: boolean;
|
|
22
24
|
}
|
|
23
25
|
interface IRcFileConfig {
|
|
@@ -39,7 +41,9 @@ interface IRcFileConfig {
|
|
|
39
41
|
maxgzipsize?: number | string;
|
|
40
42
|
noindexcheck?: boolean;
|
|
41
43
|
dryrun?: boolean;
|
|
44
|
+
analyze?: boolean;
|
|
42
45
|
spa?: boolean;
|
|
46
|
+
manifest?: boolean;
|
|
43
47
|
}
|
|
44
48
|
declare function validateCppIdentifier(value: string, name: string): string;
|
|
45
49
|
declare function parseSize(value: string, name: string): number;
|
package/dist/commandLine.js
CHANGED
|
@@ -25,7 +25,7 @@ Configuration:
|
|
|
25
25
|
Options:
|
|
26
26
|
-e, --engine <value> The engine for which the include file is created
|
|
27
27
|
(psychic|async|espidf|webserver) (default: "psychic")
|
|
28
|
-
-s, --sourcepath <path> Source dist folder
|
|
28
|
+
-s, --sourcepath <path> Source dist folder with compiled web files (required)
|
|
29
29
|
-o, --outputfile <path> Generated output file with path (default: "svelteesp32.h")
|
|
30
30
|
--etag <value> Use ETAG header for cache (true|false|compiler) (default: "false")
|
|
31
31
|
--gzip <value> Compress content with gzip (true|false|compiler) (default: "true")
|
|
@@ -42,8 +42,10 @@ Options:
|
|
|
42
42
|
--maxsize <size> Maximum total uncompressed size (e.g., 400k, 1.5m, 409600)
|
|
43
43
|
--maxgzipsize <size> Maximum total gzip size (e.g., 150k, 1m, 153600)
|
|
44
44
|
--dryrun Show summary without writing the output file (default: false)
|
|
45
|
+
--analyze Print per-file size table and budget status without writing (default: false)
|
|
45
46
|
--spa Serve index.html for unmatched routes (SPA routing) (default: false)
|
|
46
|
-
|
|
47
|
+
--manifest Write companion JSON manifest file alongside the header (default: false)
|
|
48
|
+
-h, --help Show this help
|
|
47
49
|
|
|
48
50
|
RC File:
|
|
49
51
|
The tool searches for .svelteesp32rc.json in:
|
|
@@ -287,7 +289,9 @@ function validateRcConfig(config, rcPath) {
|
|
|
287
289
|
'maxgzipsize',
|
|
288
290
|
'noindexcheck',
|
|
289
291
|
'dryrun',
|
|
290
|
-
'
|
|
292
|
+
'analyze',
|
|
293
|
+
'spa',
|
|
294
|
+
'manifest'
|
|
291
295
|
]);
|
|
292
296
|
for (const key of Object.keys(configObject))
|
|
293
297
|
if (!validKeys.has(key))
|
|
@@ -333,8 +337,12 @@ function validateRcConfig(config, rcPath) {
|
|
|
333
337
|
throw new TypeError(`Invalid noindexcheck in RC file: ${configObject['noindexcheck']} (must be boolean)`);
|
|
334
338
|
if (configObject['dryrun'] !== undefined && typeof configObject['dryrun'] !== 'boolean')
|
|
335
339
|
throw new TypeError(`Invalid dryrun in RC file: ${configObject['dryrun']} (must be boolean)`);
|
|
340
|
+
if (configObject['analyze'] !== undefined && typeof configObject['analyze'] !== 'boolean')
|
|
341
|
+
throw new TypeError(`Invalid analyze in RC file: ${configObject['analyze']} (must be boolean)`);
|
|
336
342
|
if (configObject['spa'] !== undefined && typeof configObject['spa'] !== 'boolean')
|
|
337
343
|
throw new TypeError(`Invalid spa in RC file: ${configObject['spa']} (must be boolean)`);
|
|
344
|
+
if (configObject['manifest'] !== undefined && typeof configObject['manifest'] !== 'boolean')
|
|
345
|
+
throw new TypeError(`Invalid manifest in RC file: ${configObject['manifest']} (must be boolean)`);
|
|
338
346
|
if (configObject['outputfile'] !== undefined && node_path_1.default.isAbsolute(configObject['outputfile']))
|
|
339
347
|
throw new Error(`'outputfile' in RC file must be a relative path (use --output CLI flag for absolute paths): ${configObject['outputfile']}`);
|
|
340
348
|
return configObject;
|
|
@@ -409,8 +417,12 @@ function parseArguments() {
|
|
|
409
417
|
result.noIndexCheck = rcConfig.noindexcheck;
|
|
410
418
|
if (rcConfig.dryrun !== undefined)
|
|
411
419
|
result.dryRun = rcConfig.dryrun;
|
|
420
|
+
if (rcConfig.analyze !== undefined)
|
|
421
|
+
result.analyze = rcConfig.analyze;
|
|
412
422
|
if (rcConfig.spa !== undefined)
|
|
413
423
|
result.spa = rcConfig.spa;
|
|
424
|
+
if (rcConfig.manifest !== undefined)
|
|
425
|
+
result.manifest = rcConfig.manifest;
|
|
414
426
|
if (rcConfig.exclude && rcConfig.exclude.length > 0)
|
|
415
427
|
result.exclude = [...rcConfig.exclude];
|
|
416
428
|
const cliExclude = [];
|
|
@@ -513,10 +525,18 @@ function parseArguments() {
|
|
|
513
525
|
result.dryRun = true;
|
|
514
526
|
continue;
|
|
515
527
|
}
|
|
528
|
+
if (argument === '--analyze') {
|
|
529
|
+
result.analyze = true;
|
|
530
|
+
continue;
|
|
531
|
+
}
|
|
516
532
|
if (argument === '--spa') {
|
|
517
533
|
result.spa = true;
|
|
518
534
|
continue;
|
|
519
535
|
}
|
|
536
|
+
if (argument === '--manifest') {
|
|
537
|
+
result.manifest = true;
|
|
538
|
+
continue;
|
|
539
|
+
}
|
|
520
540
|
if (argument.startsWith('-') && !argument.startsWith('--')) {
|
|
521
541
|
const flag = argument.slice(1);
|
|
522
542
|
const nextArgument = arguments_[index + 1];
|
|
@@ -557,6 +577,8 @@ function parseArguments() {
|
|
|
557
577
|
console.error('Error: --sourcepath is required (can be specified in RC file or CLI)');
|
|
558
578
|
showHelp();
|
|
559
579
|
}
|
|
580
|
+
if (result.dryRun && result.analyze)
|
|
581
|
+
throw new Error('--analyze and --dryrun are mutually exclusive. Use --analyze for CI budget checks or --dryrun for a developer route preview.');
|
|
560
582
|
return result;
|
|
561
583
|
}
|
|
562
584
|
function formatConfiguration(cmdLine) {
|
|
@@ -588,6 +610,8 @@ function formatConfiguration(cmdLine) {
|
|
|
588
610
|
parts.push(`maxGzipSize=${cmdLine.maxGzipSize}`);
|
|
589
611
|
if (cmdLine.spa)
|
|
590
612
|
parts.push(`spa=${cmdLine.spa}`);
|
|
613
|
+
if (cmdLine.analyze)
|
|
614
|
+
parts.push(`analyze=${cmdLine.analyze}`);
|
|
591
615
|
if (cmdLine.exclude.length > 0)
|
|
592
616
|
parts.push(`exclude=[${cmdLine.exclude.join(', ')}]`);
|
|
593
617
|
return parts.join(' ').replace(/[\n\r]/g, ' ');
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
import { CppCodeSource, CppCodeSources, ExtensionGroups } from './cppCode';
|
|
2
|
+
type ProcessingSummary = {
|
|
3
|
+
filecount: number;
|
|
4
|
+
size: number;
|
|
5
|
+
gzipsize: number;
|
|
6
|
+
};
|
|
2
7
|
declare const shouldUseGzip: (originalSize: number, compressedSize: number) => boolean;
|
|
3
8
|
declare const calculateCompressionRatio: (originalSize: number, compressedSize: number) => number;
|
|
4
9
|
declare const formatCompressionLog: (filename: string, padding: string, originalSize: number, compressedSize: number, useGzip: boolean) => string;
|
|
5
10
|
declare const formatSize: (bytes: number) => string;
|
|
11
|
+
declare const formatSizePrecise: (bytes: number) => string;
|
|
6
12
|
declare const createSourceEntry: (filename: string, dataname: string, content: Buffer, contentGzip: Buffer, mimeType: string, sha256: string, isGzip: boolean) => CppCodeSource;
|
|
7
13
|
declare const updateExtensionGroup: (filesByExtension: ExtensionGroups, extension: string) => void;
|
|
8
14
|
declare const formatDryRunRoutes: (sources: CppCodeSources, engine: "psychic" | "async" | "espidf" | "webserver", basePath: string, spa: boolean) => string;
|
|
15
|
+
declare const formatAnalyzeTable: (sources: CppCodeSources, summary: ProcessingSummary, maxSize: number | undefined, maxGzipSize: number | undefined) => string;
|
|
9
16
|
export declare function main(): void;
|
|
10
|
-
export { calculateCompressionRatio, createSourceEntry, formatCompressionLog, formatDryRunRoutes, formatSize, shouldUseGzip, updateExtensionGroup };
|
|
17
|
+
export { calculateCompressionRatio, createSourceEntry, formatAnalyzeTable, formatCompressionLog, formatDryRunRoutes, formatSize, formatSizePrecise, shouldUseGzip, updateExtensionGroup };
|
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.updateExtensionGroup = exports.shouldUseGzip = exports.formatSize = exports.formatDryRunRoutes = exports.formatCompressionLog = exports.createSourceEntry = exports.calculateCompressionRatio = void 0;
|
|
6
|
+
exports.updateExtensionGroup = exports.shouldUseGzip = exports.formatSizePrecise = exports.formatSize = exports.formatDryRunRoutes = exports.formatCompressionLog = exports.formatAnalyzeTable = exports.createSourceEntry = exports.calculateCompressionRatio = void 0;
|
|
7
7
|
exports.main = main;
|
|
8
8
|
const node_fs_1 = require("node:fs");
|
|
9
9
|
const node_path_1 = __importDefault(require("node:path"));
|
|
@@ -35,6 +35,12 @@ const formatSize = (bytes) => {
|
|
|
35
35
|
return `${Math.round(bytes / 1024)}kB`;
|
|
36
36
|
};
|
|
37
37
|
exports.formatSize = formatSize;
|
|
38
|
+
const formatSizePrecise = (bytes) => {
|
|
39
|
+
if (bytes < 1024)
|
|
40
|
+
return `${bytes}B`;
|
|
41
|
+
return `${(bytes / 1024).toFixed(1)}kB`;
|
|
42
|
+
};
|
|
43
|
+
exports.formatSizePrecise = formatSizePrecise;
|
|
38
44
|
const createSourceEntry = (filename, dataname, content, contentGzip, mimeType, sha256, isGzip) => ({
|
|
39
45
|
filename,
|
|
40
46
|
dataname,
|
|
@@ -94,6 +100,39 @@ const formatDryRunRoutes = (sources, engine, basePath, spa) => {
|
|
|
94
100
|
.join('\n');
|
|
95
101
|
};
|
|
96
102
|
exports.formatDryRunRoutes = formatDryRunRoutes;
|
|
103
|
+
const formatAnalyzeTable = (sources, summary, maxSize, maxGzipSize) => {
|
|
104
|
+
const rows = sources.map((s) => ({
|
|
105
|
+
file: s.filename,
|
|
106
|
+
orig: formatSizePrecise(s.content.length),
|
|
107
|
+
gzip: formatSizePrecise(s.isGzip ? s.contentGzip.length : s.content.length),
|
|
108
|
+
tag: s.isGzip ? '' : '[no gzip]'
|
|
109
|
+
}));
|
|
110
|
+
const fileWidth = Math.max(4, ...rows.map((r) => r.file.length), 'Total'.length);
|
|
111
|
+
const origWidth = Math.max(8, ...rows.map((r) => r.orig.length), formatSizePrecise(summary.size).length);
|
|
112
|
+
const gzipWidth = Math.max(8, ...rows.map((r) => r.gzip.length), formatSizePrecise(summary.gzipsize).length);
|
|
113
|
+
const separator = `${'─'.repeat(fileWidth)} ${'─'.repeat(origWidth)} ${'─'.repeat(gzipWidth)}`;
|
|
114
|
+
const header = `${'File'.padEnd(fileWidth)} ${'Original'.padEnd(origWidth)} ${'Gzip'.padEnd(gzipWidth)}`;
|
|
115
|
+
const dataRows = rows.map((r) => {
|
|
116
|
+
const tagPart = r.tag ? ` ${r.tag}` : '';
|
|
117
|
+
return `${r.file.padEnd(fileWidth)} ${r.orig.padEnd(origWidth)} ${r.gzip.padEnd(gzipWidth)}${tagPart}`.trimEnd();
|
|
118
|
+
});
|
|
119
|
+
const totalOrig = formatSizePrecise(summary.size);
|
|
120
|
+
const totalGzip = formatSizePrecise(summary.gzipsize);
|
|
121
|
+
const totalRow = `${'Total'.padEnd(fileWidth)} ${totalOrig.padEnd(origWidth)} ${totalGzip.padEnd(gzipWidth)}`;
|
|
122
|
+
const lines = [header, separator, ...dataRows, separator, totalRow];
|
|
123
|
+
if (maxSize !== undefined) {
|
|
124
|
+
const pass = summary.size <= maxSize;
|
|
125
|
+
const budgetRow = `${'Budget (maxsize)'.padEnd(fileWidth)} ${formatSizePrecise(maxSize).padEnd(origWidth)} ${'-'.padEnd(gzipWidth)} ${pass ? '✓ PASS' : '✗ FAIL'}`;
|
|
126
|
+
lines.push(budgetRow);
|
|
127
|
+
}
|
|
128
|
+
if (maxGzipSize !== undefined) {
|
|
129
|
+
const pass = summary.gzipsize <= maxGzipSize;
|
|
130
|
+
const budgetRow = `${'Budget (maxgzipsize)'.padEnd(fileWidth)} ${'-'.padEnd(origWidth)} ${formatSizePrecise(maxGzipSize).padEnd(gzipWidth)} ${pass ? '✓ PASS' : '✗ FAIL'}`;
|
|
131
|
+
lines.push(budgetRow);
|
|
132
|
+
}
|
|
133
|
+
return lines.join('\n');
|
|
134
|
+
};
|
|
135
|
+
exports.formatAnalyzeTable = formatAnalyzeTable;
|
|
97
136
|
function main() {
|
|
98
137
|
const summary = {
|
|
99
138
|
filecount: 0,
|
|
@@ -138,6 +177,14 @@ function main() {
|
|
|
138
177
|
}
|
|
139
178
|
console.log('');
|
|
140
179
|
filesByExtension.sort((left, right) => left.extension.localeCompare(right.extension));
|
|
180
|
+
if (commandLine_1.cmdLine.analyze) {
|
|
181
|
+
console.log(formatAnalyzeTable(sources, summary, commandLine_1.cmdLine.maxSize, commandLine_1.cmdLine.maxGzipSize));
|
|
182
|
+
const overBudget = (commandLine_1.cmdLine.maxSize !== undefined && summary.size > commandLine_1.cmdLine.maxSize) ||
|
|
183
|
+
(commandLine_1.cmdLine.maxGzipSize !== undefined && summary.gzipsize > commandLine_1.cmdLine.maxGzipSize);
|
|
184
|
+
if (overBudget)
|
|
185
|
+
process.exit(1);
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
141
188
|
if (commandLine_1.cmdLine.maxSize !== undefined && summary.size > commandLine_1.cmdLine.maxSize) {
|
|
142
189
|
console.error((0, errorMessages_1.getSizeBudgetExceededError)('size', commandLine_1.cmdLine.maxSize, summary.size));
|
|
143
190
|
process.exit(1);
|
|
@@ -161,6 +208,27 @@ function main() {
|
|
|
161
208
|
(0, node_fs_1.writeFileSync)(commandLine_1.cmdLine.outputfile, cppFile, { flush: true, encoding: 'utf8' });
|
|
162
209
|
console.log(`${summary.filecount} files, ${formatSize(summary.size)} original size, ${formatSize(summary.gzipsize)} gzip size`);
|
|
163
210
|
console.log(`${commandLine_1.cmdLine.outputfile} ${formatSize(cppFile.length)} size`);
|
|
211
|
+
if (commandLine_1.cmdLine.manifest) {
|
|
212
|
+
const manifestPath = node_path_1.default.join(node_path_1.default.dirname(commandLine_1.cmdLine.outputfile), node_path_1.default.basename(commandLine_1.cmdLine.outputfile, node_path_1.default.extname(commandLine_1.cmdLine.outputfile)) + '.manifest.json');
|
|
213
|
+
const manifest = {
|
|
214
|
+
generated: new Date().toISOString(),
|
|
215
|
+
engine: commandLine_1.cmdLine.engine,
|
|
216
|
+
etag: commandLine_1.cmdLine.etag,
|
|
217
|
+
gzip: commandLine_1.cmdLine.gzip,
|
|
218
|
+
filecount: summary.filecount,
|
|
219
|
+
size: summary.size,
|
|
220
|
+
gzipSize: summary.gzipsize,
|
|
221
|
+
files: sources.map((s) => ({
|
|
222
|
+
path: s.filename,
|
|
223
|
+
mime: s.mime,
|
|
224
|
+
size: s.content.length,
|
|
225
|
+
gzipSize: s.isGzip ? s.contentGzip.length : s.content.length,
|
|
226
|
+
isGzip: s.isGzip
|
|
227
|
+
}))
|
|
228
|
+
};
|
|
229
|
+
(0, node_fs_1.writeFileSync)(manifestPath, JSON.stringify(manifest, undefined, 2), { encoding: 'utf8' });
|
|
230
|
+
console.log(`${manifestPath} manifest written`);
|
|
231
|
+
}
|
|
164
232
|
if (commandLine_1.cmdLine.engine === 'psychic' || commandLine_1.cmdLine.engine === 'espidf')
|
|
165
233
|
console.log('\n' + (0, errorMessages_1.getMaxUriHandlersHint)(commandLine_1.cmdLine.engine, sources.length, commandLine_1.cmdLine.espmethod));
|
|
166
234
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "svelteesp32",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.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",
|
|
@@ -62,27 +62,27 @@
|
|
|
62
62
|
"@eslint/eslintrc": "^3.3.5",
|
|
63
63
|
"@eslint/js": "^10.0.1",
|
|
64
64
|
"@types/mime-types": "^3.0.1",
|
|
65
|
-
"@types/node": "^25.
|
|
65
|
+
"@types/node": "^25.6.0",
|
|
66
66
|
"@types/picomatch": "^4.0.3",
|
|
67
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
68
|
-
"@typescript-eslint/parser": "^8.
|
|
69
|
-
"@vitest/coverage-v8": "^4.1.
|
|
70
|
-
"eslint": "^10.2.
|
|
67
|
+
"@typescript-eslint/eslint-plugin": "^8.59.0",
|
|
68
|
+
"@typescript-eslint/parser": "^8.59.0",
|
|
69
|
+
"@vitest/coverage-v8": "^4.1.5",
|
|
70
|
+
"eslint": "^10.2.1",
|
|
71
71
|
"eslint-config-prettier": "^10.1.8",
|
|
72
72
|
"eslint-plugin-simple-import-sort": "^13.0.0",
|
|
73
73
|
"eslint-plugin-unicorn": "^64.0.0",
|
|
74
|
-
"memfs": "^4.57.
|
|
74
|
+
"memfs": "^4.57.2",
|
|
75
75
|
"nodemon": "^3.1.14",
|
|
76
|
-
"prettier": "^3.8.
|
|
76
|
+
"prettier": "^3.8.3",
|
|
77
77
|
"ts-node": "^10.9.2",
|
|
78
78
|
"tsx": "^4.21.0",
|
|
79
|
-
"typescript": "^6.0.
|
|
80
|
-
"vitest": "^4.1.
|
|
79
|
+
"typescript": "^6.0.3",
|
|
80
|
+
"vitest": "^4.1.5"
|
|
81
81
|
},
|
|
82
82
|
"dependencies": {
|
|
83
83
|
"handlebars": "^4.7.9",
|
|
84
84
|
"mime-types": "^3.0.2",
|
|
85
85
|
"picomatch": "^4.0.4",
|
|
86
|
-
"tinyglobby": "^0.2.
|
|
86
|
+
"tinyglobby": "^0.2.16"
|
|
87
87
|
}
|
|
88
88
|
}
|