From 1d307732347d0ada46440c5cd63b343d95d04bc7 Mon Sep 17 00:00:00 2001 From: Patedam Date: Mon, 2 Mar 2026 20:47:52 -0500 Subject: [PATCH] feat: Initialize Svelte frontend with Vite, Tailwind CSS, single-file build, and a gzip script for ESP32 deployment. --- Provider/frontend/package-lock.json | 96 ++++++++++++++++++++++++++++- Provider/frontend/package.json | 6 +- Provider/frontend/scripts/gzip.js | 26 ++++++++ Provider/frontend/vite.config.js | 9 +++ 4 files changed, 134 insertions(+), 3 deletions(-) create mode 100644 Provider/frontend/scripts/gzip.js diff --git a/Provider/frontend/package-lock.json b/Provider/frontend/package-lock.json index 9eba8a1..39d2b34 100644 --- a/Provider/frontend/package-lock.json +++ b/Provider/frontend/package-lock.json @@ -12,7 +12,8 @@ "@tailwindcss/vite": "^4.2.1", "svelte": "^5.45.2", "tailwindcss": "^4.2.1", - "vite": "^7.3.1" + "vite": "^7.3.1", + "vite-plugin-singlefile": "^2.3.0" } }, "node_modules/@esbuild/aix-ppc64": { @@ -1225,6 +1226,19 @@ "node": ">= 0.4" } }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/clsx": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", @@ -1353,6 +1367,19 @@ } } }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -1375,6 +1402,16 @@ "dev": true, "license": "ISC" }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, "node_modules/is-reference": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.3.tgz", @@ -1673,6 +1710,33 @@ "@jridgewell/sourcemap-codec": "^1.5.5" } }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/nanoid": { "version": "3.3.11", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", @@ -1873,6 +1937,19 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, "node_modules/vite": { "version": "7.3.1", "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", @@ -1948,6 +2025,23 @@ } } }, + "node_modules/vite-plugin-singlefile": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/vite-plugin-singlefile/-/vite-plugin-singlefile-2.3.0.tgz", + "integrity": "sha512-DAcHzYypM0CasNLSz/WG0VdKOCxGHErfrjOoyIPiNxTPTGmO6rRD/te93n1YL/s+miXq66ipF1brMBikf99c6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">18.0.0" + }, + "peerDependencies": { + "rollup": "^4.44.1", + "vite": "^5.4.11 || ^6.0.0 || ^7.0.0" + } + }, "node_modules/vitefu": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.1.2.tgz", diff --git a/Provider/frontend/package.json b/Provider/frontend/package.json index d67134f..b729be1 100644 --- a/Provider/frontend/package.json +++ b/Provider/frontend/package.json @@ -6,6 +6,7 @@ "scripts": { "dev": "vite", "build": "vite build", + "build:esp32": "vite build && node scripts/gzip.js", "preview": "vite preview" }, "devDependencies": { @@ -13,6 +14,7 @@ "@tailwindcss/vite": "^4.2.1", "svelte": "^5.45.2", "tailwindcss": "^4.2.1", - "vite": "^7.3.1" + "vite": "^7.3.1", + "vite-plugin-singlefile": "^2.3.0" } -} +} \ No newline at end of file diff --git a/Provider/frontend/scripts/gzip.js b/Provider/frontend/scripts/gzip.js new file mode 100644 index 0000000..cebef23 --- /dev/null +++ b/Provider/frontend/scripts/gzip.js @@ -0,0 +1,26 @@ +/** + * Gzip script for ESP32 deployment. + * Compresses dist/index.html -> dist/index.html.gz + * Uses Node.js built-in zlib (no extra dependencies). + */ + +import { readFileSync, writeFileSync } from 'fs'; +import { gzipSync } from 'zlib'; +import { resolve, dirname } from 'path'; +import { fileURLToPath } from 'url'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const inputPath = resolve(__dirname, '..', 'dist', 'index.html'); +const outputPath = resolve(__dirname, '..', 'dist', 'index.html.gz'); + +const input = readFileSync(inputPath); +const compressed = gzipSync(input, { level: 9 }); + +writeFileSync(outputPath, compressed); + +const inputKB = (input.length / 1024).toFixed(1); +const outputKB = (compressed.length / 1024).toFixed(1); +const ratio = ((1 - compressed.length / input.length) * 100).toFixed(0); + +console.log(`Gzip: ${inputKB} kB -> ${outputKB} kB (${ratio}% reduction)`); +console.log(`Output: dist/index.html.gz`); diff --git a/Provider/frontend/vite.config.js b/Provider/frontend/vite.config.js index 9da938e..b53b297 100644 --- a/Provider/frontend/vite.config.js +++ b/Provider/frontend/vite.config.js @@ -1,15 +1,24 @@ import { defineConfig } from 'vite' import { svelte } from '@sveltejs/vite-plugin-svelte' import tailwindcss from '@tailwindcss/vite' +import { viteSingleFile } from 'vite-plugin-singlefile' // https://vite.dev/config/ export default defineConfig({ plugins: [ svelte(), tailwindcss(), + viteSingleFile({ + removeViteModuleLoader: true, + }), ], // Resolve the W: subst drive to avoid path mismatches on Windows resolve: { preserveSymlinks: true, }, + build: { + // Ensure everything goes into a single chunk + cssCodeSplit: false, + assetsInlineLimit: 100000, + }, })