svelteesp32 2.4.1 → 3.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 CHANGED
@@ -56,7 +56,7 @@ npm install -D svelteesp32
56
56
  After building your frontend (Vite/Rollup/Webpack):
57
57
 
58
58
  ```bash
59
- npx svelteesp32 -e psychic -s ./dist -o ./esp32/svelteesp32.h --etag=true
59
+ npx svelteesp32 -e psychic -s ./dist -o ./esp32/svelteesp32.h --etag=always
60
60
  ```
61
61
 
62
62
  Include in your ESP32 project:
@@ -79,7 +79,7 @@ void setup() {
79
79
  >
80
80
  > ```bash
81
81
  > npx svelteesp32 -e psychic -s ./dist -o ./esp32/svelteesp32.h \
82
- > --etag=true --gzip=true --cachetime-html=0 --cachetime-assets=31536000
82
+ > --etag=always --gzip=always --cachetime-html=0 --cachetime-assets=31536000
83
83
  > ```
84
84
  >
85
85
  > ETags for instant 304s, gzip for smaller transfers, `no-cache` for HTML so updates are always picked up, and 1-year caching for content-hashed JS/CSS assets.
@@ -88,6 +88,8 @@ void setup() {
88
88
 
89
89
  ## What's New
90
90
 
91
+ - **v3.0.1** — Vite plugin now reads RC file automatically; `output` is optional when `outputfile` is in the RC file; option names aligned to lowercase to match RC file keys (`cachetimehtml`, `cachetimeassets`, `noindexcheck`, `maxsize`, `maxgzipsize`); new `config` option to point at a custom RC file
92
+ - **v3.0.0** — **Vite plugin** (`import { svelteESP32 } from 'svelteesp32/vite'`) generates the header automatically after every build; `npx svelteesp32 init` interactive RC file wizard; Node.js >= 22 required
91
93
  - **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
94
  - **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)
93
95
  - **v2.2.0** — SPA routing catch-all (`--spa`) for client-side routers on all four engines
@@ -104,8 +106,8 @@ void setup() {
104
106
 
105
107
  ## Requirements
106
108
 
107
- - Node.js >= 20
108
- - npm >= 9
109
+ - Node.js >= 22
110
+ - npm >= 10
109
111
 
110
112
  ---
111
113
 
@@ -117,22 +119,85 @@ void setup() {
117
119
  npm install -D svelteesp32
118
120
  ```
119
121
 
120
- ### Generate Header File
122
+ ### Quick Setup with `init`
123
+
124
+ The `init` command creates a `.svelteesp32rc.json` configuration file interactively so you never have to remember CLI flags:
125
+
126
+ ```bash
127
+ npx svelteesp32 init
128
+ ```
129
+
130
+ It asks for engine, source path, output path, and ETag preference, writes the RC file, and optionally runs the tool immediately.
131
+
132
+ ### Vite Plugin
133
+
134
+ For Vite-based projects (SvelteKit, React, Vue, Vanilla) you can skip the manual CLI step entirely — the plugin hooks into the build pipeline and regenerates the C++ header automatically after every `vite build`.
135
+
136
+ **`vite.config.ts`**
137
+
138
+ ```ts
139
+ import { svelteKit } from '@sveltejs/kit/vite';
140
+ import { svelteESP32 } from 'svelteesp32/vite';
141
+ import { defineConfig } from 'vite';
142
+
143
+ export default defineConfig({
144
+ plugins: [
145
+ svelteKit(),
146
+ svelteESP32({
147
+ output: '../firmware/include/svelteesp32.h',
148
+ engine: 'psychic',
149
+ etag: 'always',
150
+ gzip: 'always',
151
+ cachetimehtml: 0,
152
+ cachetimeassets: 31536000
153
+ })
154
+ ]
155
+ });
156
+ ```
157
+
158
+ `output` can be omitted when `outputfile` is set in an RC file. `sourcepath` defaults to Vite's `build.outDir`. All other options mirror CLI flags and fall back to the RC file before applying built-in defaults.
159
+
160
+ **Plugin options**
161
+
162
+ | Option | Type | Default | Description |
163
+ | ----------------- | ------------------------------------------- | ------------------------- | -------------------------------------------------- |
164
+ | `output` | `string` | RC `outputfile` | Output `.h` file path |
165
+ | `sourcepath` | `string` | Vite's `build.outDir` | Source directory (compiled web files) |
166
+ | `engine` | `'psychic'\|'async'\|'espidf'\|'webserver'` | `'psychic'` | Target web server engine |
167
+ | `etag` | `'always'\|'never'\|'compiler'` | `'never'` | ETag generation mode |
168
+ | `gzip` | `'always'\|'never'\|'compiler'` | `'always'` | Gzip compression mode |
169
+ | `cachetime` | `number` | `0` | `Cache-Control: max-age` in seconds (all files) |
170
+ | `cachetimehtml` | `number` | (unset) | max-age for HTML files (overrides `cachetime`) |
171
+ | `cachetimeassets` | `number` | (unset) | max-age for non-HTML files (overrides `cachetime`) |
172
+ | `exclude` | `string[]` | `[]` | Glob patterns to exclude |
173
+ | `basepath` | `string` | (none) | URL prefix for all routes |
174
+ | `espmethod` | `string` | `'initSvelteStaticFiles'` | Generated init function name |
175
+ | `define` | `string` | `'SVELTEESP32'` | C++ `#define` prefix |
176
+ | `version` | `string` | (none) | Version string embedded in header |
177
+ | `created` | `boolean` | `false` | Include creation timestamp |
178
+ | `spa` | `boolean` | `false` | Serve `index.html` for unmatched routes |
179
+ | `manifest` | `boolean` | `false` | Write companion `.manifest.json` |
180
+ | `noindexcheck` | `boolean` | `false` | Skip `index.html` validation |
181
+ | `maxsize` | `number` | (none) | Max total uncompressed size in bytes |
182
+ | `maxgzipsize` | `number` | (none) | Max total gzip size in bytes |
183
+ | `config` | `string` | auto-discover | Path to a custom RC file |
184
+
185
+ ### Generate Header File (CLI)
121
186
 
122
187
  Choose your web server engine:
123
188
 
124
189
  ```bash
125
190
  # PsychicHttpServer (recommended for ESP32)
126
- npx svelteesp32 -e psychic -s ./dist -o ./esp32/svelteesp32.h --etag=true
191
+ npx svelteesp32 -e psychic -s ./dist -o ./esp32/svelteesp32.h --etag=always
127
192
 
128
193
  # ESPAsyncWebServer (ESP32 + ESP8266)
129
- npx svelteesp32 -e async -s ./dist -o ./esp32/svelteesp32.h --etag=true
194
+ npx svelteesp32 -e async -s ./dist -o ./esp32/svelteesp32.h --etag=always
130
195
 
131
196
  # Arduino WebServer (ESP32, synchronous, no dependencies)
132
- npx svelteesp32 -e webserver -s ./dist -o ./esp32/svelteesp32.h --etag=true
197
+ npx svelteesp32 -e webserver -s ./dist -o ./esp32/svelteesp32.h --etag=always
133
198
 
134
199
  # Native ESP-IDF
135
- npx svelteesp32 -e espidf -s ./dist -o ./esp32/svelteesp32.h --etag=true
200
+ npx svelteesp32 -e espidf -s ./dist -o ./esp32/svelteesp32.h --etag=always
136
201
  ```
137
202
 
138
203
  ### Build Output
@@ -227,7 +292,7 @@ The generated header file includes everything your ESP needs:
227
292
 
228
293
  ```c
229
294
  //engine: PsychicHttpServer V2
230
- //config: engine=psychic sourcepath=./dist outputfile=./output.h etag=true gzip=true cachetime=0 espmethod=initSvelteStaticFiles define=SVELTEESP32
295
+ //config: engine=psychic sourcepath=./dist outputfile=./output.h etag=always gzip=always cachetime=0 espmethod=initSvelteStaticFiles define=SVELTEESP32
231
296
  //
232
297
  #define SVELTEESP32_COUNT 5
233
298
  #define SVELTEESP32_SIZE 468822
@@ -311,20 +376,20 @@ void initSvelteStaticFiles(PsychicHttpServer * server) {
311
376
 
312
377
  Your JS, CSS, and HTML files are automatically compressed at build time — not on the ESP32. Files are gzipped when they're >1KB and achieve >15% size reduction.
313
378
 
314
- - **Enabled by default** — disable with `--gzip=false`
379
+ - **Enabled by default** — disable with `--gzip=never`
315
380
  - **Compiler mode** — use `--gzip=compiler` and control via `-D SVELTEESP32_ENABLE_GZIP` in PlatformIO
316
381
 
317
382
  ### Smart ETag Caching
318
383
 
319
384
  Reduce bandwidth dramatically with HTTP 304 "Not Modified" responses. When a browser has a cached file, the ESP32 sends just a status code instead of the entire file — perfect for bandwidth-constrained IoT devices.
320
385
 
321
- - **Enable with** `--etag=true` (recommended)
386
+ - **Enable with** `--etag=always` (recommended)
322
387
  - **Minimal overhead** — adds ~1-3% code size for significant bandwidth savings
323
388
  - **Compiler mode** — use `--etag=compiler` and control via `-D SVELTEESP32_ENABLE_ETAG`
324
389
 
325
390
  All four engines support full ETag validation.
326
391
 
327
- > **Browser compatibility note:** ETags and `Cache-Control: max-age` are universally supported in all modern browsers. Very old clients (IE6/7, early Android 2.x WebViews) may ignore `must-revalidate` or mishandle 304 responses. If you target these environments, set `--etag=false` and `--cachetime=0` to force full downloads on every request.
392
+ > **Browser compatibility note:** ETags and `Cache-Control: max-age` are universally supported in all modern browsers. Very old clients (IE6/7, early Android 2.x WebViews) may ignore `must-revalidate` or mishandle 304 responses. If you target these environments, set `--etag=never` and `--cachetime=0` to force full downloads on every request.
328
393
 
329
394
  ### Browser Cache Control
330
395
 
@@ -338,7 +403,7 @@ Vite and webpack produce content-hashed filenames for JS/CSS (e.g., `app.a1b2c3.
338
403
 
339
404
  ```bash
340
405
  npx svelteesp32 -e psychic -s ./dist -o ./output.h \
341
- --etag=true --cachetime-html=0 --cachetime-assets=31536000
406
+ --etag=always --cachetime-html=0 --cachetime-assets=31536000
342
407
  ```
343
408
 
344
409
  This emits `Cache-Control: no-cache` for every `text/html` file and `Cache-Control: max-age=31536000` for all other assets in the same header, with no per-file configuration needed.
@@ -465,8 +530,8 @@ The manifest records build metadata and per-file details for tooling and dashboa
465
530
  {
466
531
  "generated": "2026-04-26T12:00:00.000Z",
467
532
  "engine": "psychic",
468
- "etag": "false",
469
- "gzip": "true",
533
+ "etag": "never",
534
+ "gzip": "always",
470
535
  "filecount": 4,
471
536
  "size": 104960,
472
537
  "gzipSize": 51507,
@@ -536,8 +601,8 @@ Called for every response (200 = content served, 304 = cache hit).
536
601
  | `-s` | Source folder with compiled web files | (required) |
537
602
  | `-e` | Web server engine (psychic/async/espidf/webserver) | `psychic` |
538
603
  | `-o` | Output header file path | `svelteesp32.h` |
539
- | `--etag` | ETag caching (true/false/compiler) | `false` |
540
- | `--gzip` | Gzip compression (true/false/compiler) | `true` |
604
+ | `--etag` | ETag caching (always/never/compiler) | `never` |
605
+ | `--gzip` | Gzip compression (always/never/compiler) | `always` |
541
606
  | `--created` | Include creation timestamp in header | `false` |
542
607
  | `--exclude` | Exclude files by glob pattern | (none) |
543
608
  | `--basepath` | URL prefix for all routes | (none) |
@@ -568,8 +633,8 @@ Store your settings in `.svelteesp32rc.json` for zero-argument builds:
568
633
  "engine": "psychic",
569
634
  "sourcepath": "./dist",
570
635
  "outputfile": "./esp32/svelteesp32.h",
571
- "etag": "true",
572
- "gzip": "true",
636
+ "etag": "always",
637
+ "gzip": "always",
573
638
  "exclude": ["*.map", "*.md"],
574
639
  "basepath": "/ui",
575
640
  "maxsize": "400k",
@@ -630,10 +695,10 @@ npm run build
630
695
 
631
696
  # 2. Generate the header
632
697
  npx svelteesp32 -e webserver -s ./dist -o ./MyProject/svelteesp32.h \
633
- --gzip=true --etag=false
698
+ --gzip=always --etag=never
634
699
  ```
635
700
 
636
- > **Note:** The Arduino `WebServer` library does not support ETag validation, so `--etag=false` is the correct setting here. Remember to call `server.handleClient()` in your `loop()`.
701
+ > **Note:** The Arduino `WebServer` library does not support ETag validation, so `--etag=never` is the correct setting here. Remember to call `server.handleClient()` in your `loop()`.
637
702
 
638
703
  ```c
639
704
  #include <WebServer.h>
@@ -685,7 +750,7 @@ def build_frontend(source, target, env):
685
750
  "-e", "async",
686
751
  "-s", "frontend/dist",
687
752
  "-o", "src/svelteesp32.h",
688
- "--etag=true", "--gzip=true",
753
+ "--etag=always", "--gzip=always",
689
754
  "--cachetime-html=0", "--cachetime-assets=31536000"
690
755
  ], check=True)
691
756
 
@@ -710,7 +775,7 @@ add_custom_command(
710
775
  -e espidf
711
776
  -s ${CMAKE_CURRENT_SOURCE_DIR}/frontend/dist
712
777
  -o ${CMAKE_CURRENT_SOURCE_DIR}/main/svelteesp32.h
713
- --etag=true --gzip=true
778
+ --etag=always --gzip=always
714
779
  --cachetime-html=0 --cachetime-assets=31536000
715
780
  WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
716
781
  COMMENT "Generating svelteesp32.h from frontend build"
package/bin/index.js CHANGED
@@ -1,2 +1,11 @@
1
1
  #! /usr/bin/env node
2
- const start = require('../dist/index.js');
2
+ if (process.argv[2] === 'init') {
3
+ require('../dist/initCommand.js')
4
+ .runInit()
5
+ .catch((err) => {
6
+ console.error('Error:', err instanceof Error ? err.message : String(err));
7
+ process.exit(1);
8
+ });
9
+ } else {
10
+ require('../dist/index.js').main();
11
+ }
@@ -1,11 +1,11 @@
1
- interface ICopyFilesArguments {
1
+ export interface ICopyFilesArguments {
2
2
  engine: 'psychic' | 'async' | 'espidf' | 'webserver';
3
3
  sourcepath: string;
4
4
  outputfile: string;
5
5
  espmethod: string;
6
6
  define: string;
7
- gzip: 'true' | 'false' | 'compiler';
8
- etag: 'true' | 'false' | 'compiler';
7
+ gzip: 'always' | 'never' | 'compiler';
8
+ etag: 'always' | 'never' | 'compiler';
9
9
  cachetime: number;
10
10
  cachetimeHtml?: number;
11
11
  cachetimeAssets?: number;
@@ -22,14 +22,14 @@ interface ICopyFilesArguments {
22
22
  manifest?: boolean;
23
23
  help?: boolean;
24
24
  }
25
- interface IRcFileConfig {
25
+ export interface IRcFileConfig {
26
26
  engine?: 'psychic' | 'async' | 'espidf' | 'webserver';
27
27
  sourcepath?: string;
28
28
  outputfile?: string;
29
29
  espmethod?: string;
30
30
  define?: string;
31
- gzip?: 'true' | 'false' | 'compiler';
32
- etag?: 'true' | 'false' | 'compiler';
31
+ gzip?: 'always' | 'never' | 'compiler';
32
+ etag?: 'always' | 'never' | 'compiler';
33
33
  cachetime?: number;
34
34
  cachetimehtml?: number;
35
35
  cachetimeassets?: number;
@@ -46,10 +46,12 @@ interface IRcFileConfig {
46
46
  manifest?: boolean | 'true' | 'false';
47
47
  }
48
48
  declare function validateCppIdentifier(value: string, name: string): string;
49
+ export declare function validateBasePath(value: string): string;
49
50
  declare function parseSize(value: string, name: string): number;
50
51
  declare function getNpmPackageVariable(packageJson: Record<string, unknown>, variableName: string): string | undefined;
51
52
  declare function hasNpmVariables(config: IRcFileConfig): boolean;
52
53
  declare function interpolateNpmVariables(config: IRcFileConfig, rcFilePath: string): IRcFileConfig;
54
+ export declare function loadRcFileConfig(configPath?: string): Partial<IRcFileConfig>;
55
+ export declare function parseArguments(): ICopyFilesArguments;
53
56
  export { getNpmPackageVariable, hasNpmVariables, interpolateNpmVariables, parseSize, validateCppIdentifier };
54
57
  export declare function formatConfiguration(cmdLine: ICopyFilesArguments): string;
55
- export declare const cmdLine: ICopyFilesArguments;
@@ -3,7 +3,9 @@ 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.cmdLine = void 0;
6
+ exports.validateBasePath = validateBasePath;
7
+ exports.loadRcFileConfig = loadRcFileConfig;
8
+ exports.parseArguments = parseArguments;
7
9
  exports.getNpmPackageVariable = getNpmPackageVariable;
8
10
  exports.hasNpmVariables = hasNpmVariables;
9
11
  exports.interpolateNpmVariables = interpolateNpmVariables;
@@ -19,6 +21,9 @@ function showHelp() {
19
21
  console.log(`
20
22
  svelteesp32 - Svelte JS to ESP32 converter
21
23
 
24
+ Commands:
25
+ init Create .svelteesp32rc.json interactively
26
+
22
27
  Configuration:
23
28
  --config <path> Use custom RC file (default: search for .svelteesp32rc.json)
24
29
 
@@ -27,8 +32,8 @@ Options:
27
32
  (psychic|async|espidf|webserver) (default: "psychic")
28
33
  -s, --sourcepath <path> Source dist folder with compiled web files (required)
29
34
  -o, --outputfile <path> Generated output file with path (default: "svelteesp32.h")
30
- --etag <value> Use ETAG header for cache (true|false|compiler) (default: "false")
31
- --gzip <value> Compress content with gzip (true|false|compiler) (default: "true")
35
+ --etag <value> Use ETAG header for cache (always|never|compiler) (default: "never")
36
+ --gzip <value> Compress content with gzip (always|never|compiler) (default: "always")
32
37
  --created Include creation time in the output file (default: false)
33
38
  --version <value> Include version info in the output file (default: "")
34
39
  --espmethod <name> Name of generated method (default: "initSvelteStaticFiles")
@@ -57,8 +62,8 @@ RC File:
57
62
  "engine": "psychic",
58
63
  "sourcepath": "./dist",
59
64
  "outputfile": "./output.h",
60
- "etag": "true",
61
- "gzip": "true",
65
+ "etag": "always",
66
+ "gzip": "always",
62
67
  "exclude": ["*.map", "*.md"],
63
68
  "basepath": "/ui",
64
69
  "maxsize": "400k",
@@ -78,7 +83,7 @@ function validateEngine(value) {
78
83
  process.exit(1);
79
84
  }
80
85
  function validateTriState(value, name) {
81
- if (value === 'true' || value === 'false' || value === 'compiler')
86
+ if (value === 'always' || value === 'never' || value === 'compiler')
82
87
  return value;
83
88
  throw new Error(`Invalid ${name}: ${value}`);
84
89
  }
@@ -252,6 +257,12 @@ function loadRcFile(rcPath) {
252
257
  throw error;
253
258
  }
254
259
  }
260
+ function loadRcFileConfig(configPath) {
261
+ const rcPath = findRcFile(configPath);
262
+ if (!rcPath)
263
+ return {};
264
+ return loadRcFile(rcPath);
265
+ }
255
266
  function validateSizeOption(configObject, key) {
256
267
  const value = configObject[key];
257
268
  if (value === undefined)
@@ -393,8 +404,8 @@ function parseArguments() {
393
404
  const result = {
394
405
  engine: 'psychic',
395
406
  outputfile: 'svelteesp32.h',
396
- etag: 'false',
397
- gzip: 'true',
407
+ etag: 'never',
408
+ gzip: 'always',
398
409
  created: false,
399
410
  version: '',
400
411
  espmethod: 'initSvelteStaticFiles',
@@ -522,8 +533,10 @@ function parseArguments() {
522
533
  const argument = arguments_[index];
523
534
  if (!argument)
524
535
  continue;
525
- if (argument === '--help' || argument === '-h')
536
+ if (argument === '--help' || argument === '-h') {
526
537
  showHelp();
538
+ return result;
539
+ }
527
540
  if (argument.startsWith('--') && argument.includes('=')) {
528
541
  const parts = argument.split('=');
529
542
  const flag = parts[0];
@@ -636,13 +649,3 @@ function formatConfiguration(cmdLine) {
636
649
  parts.push(`exclude=[${cmdLine.exclude.join(', ')}]`);
637
650
  return parts.join(' ').replace(/[\n\r]/g, ' ');
638
651
  }
639
- exports.cmdLine = parseArguments();
640
- if (!(0, node_fs_1.existsSync)(exports.cmdLine.sourcepath)) {
641
- console.error((0, errorMessages_1.getSourcepathNotFoundError)(exports.cmdLine.sourcepath, 'not_found'));
642
- process.exit(1);
643
- }
644
- if (!(0, node_fs_1.statSync)(exports.cmdLine.sourcepath).isDirectory()) {
645
- console.error((0, errorMessages_1.getSourcepathNotFoundError)(exports.cmdLine.sourcepath, 'not_directory'));
646
- process.exit(1);
647
- }
648
- console.log(`[SvelteESP32] Generate code for ${exports.cmdLine.engine} engine`);
package/dist/cppCode.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import type { ICopyFilesArguments } from './commandLine';
1
2
  export type CppCodeSource = {
2
3
  filename: string;
3
4
  dataname: string;
@@ -14,4 +15,4 @@ export type ExtensionGroup = {
14
15
  count: number;
15
16
  };
16
17
  export type ExtensionGroups = ExtensionGroup[];
17
- export declare const getCppCode: (sources: CppCodeSources, filesByExtension: ExtensionGroups) => string;
18
+ export declare const getCppCode: (sources: CppCodeSources, filesByExtension: ExtensionGroups, options: ICopyFilesArguments) => string;