From c4928e5546f9c55f36ef148eacab5ddc5cd0837d Mon Sep 17 00:00:00 2001 From: eraiza0816 <10572974+eraiza0816@users.noreply.github.com> Date: Tue, 11 Aug 2026 06:38:55 +0900 Subject: [PATCH] docs(webui): describe the single-page layout and updated numbers The Web UI is now 8 files at 25,302 bytes gzip (23.0 % of the raw 109,814); section switching measured on a real device. --- doc/webui-compression.md | 56 +++++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 23 deletions(-) diff --git a/doc/webui-compression.md b/doc/webui-compression.md index 4839e08f..39f2b1d1 100644 --- a/doc/webui-compression.md +++ b/doc/webui-compression.md @@ -11,18 +11,24 @@ html/ --(minify.py)--> output/html_min/ --(fileadder -z)--> flash image ``` - `tools/minify.py` removes comments (``, `//`, `/* */`) and - line-leading whitespace without touching string literals, so the output - is functionally identical to the input. Binary files (`.ico`) are - copied through unchanged. The raw sources in `html/` stay untouched - for development; the minified copy in `output/` is a pure build - artifact. Comments and indentation are pure overhead for the served - bytes, so minification alone already reduces the transfer size from - 111,280 to 99,715 bytes, independent of gzip. -- The per-page scripts are consolidated into a single `html/main.js` - bundle (i18n, shared helpers, navigation and the page scripts). Every - page loads only this one script, so the browser fetches it once and - gzip can compress across all of it. The page-specific initialisation - runs only when the matching page elements are present. + line-leading whitespace without touching string or regex literals, so + the output is functionally identical to the input. Binary files + (`.ico`) are copied through unchanged. The raw sources in `html/` stay + untouched for development; the minified copy in `output/` is a pure + build artifact. Comments and indentation are pure overhead for the + served bytes, so minification alone already reduces the transfer size + from 109,814 to 97,730 bytes, independent of gzip. +- The Web UI is a single-page application: `index.html` holds all pages + as sections (`#/ports`, `#/vlan`, ...) that the sidebar switches + between via the URL hash. `login.html` stays separate because it is + the authentication gate. Only these two pages plus `main.js`, + `style.css`, the three SVG port images and the favicon are embedded. +- All JavaScript (i18n, shared helpers, navigation and the per-section + scripts) lives in one `html/main.js` bundle that the pages load as + their only script, so the browser fetches it once and gzip can + compress across all of it. A section's initialisation runs when the + section is shown, its polling intervals run only while it is visible, + and re-entering a section refetches the data. - `fileadder -z` gzip-compresses every file (zlib, gzip format, `Z_BEST_COMPRESSION`) when it generates the file table (`html_data.c`/`html_data.h`) and when it embeds the files into the @@ -41,27 +47,31 @@ Build on any machine (the Web UI is machine-independent): | | bytes | |---|---:| -| raw sources | 111,280 | -| minified (comments and indentation removed) | 99,715 | -| gzip (flash + wire) | 28,200 (25.3 %) | +| raw sources | 109,814 | +| minified (comments and indentation removed) | 97,730 | +| gzip (flash + wire) | 25,302 (23.0 %) | The minified assets are also what the browser receives when gzip support is missing or disabled, so the transfer size drops in both stages: -111,280 → 99,715 bytes from minification, then → 28,200 bytes from gzip. +109,814 → 97,730 bytes from minification, then → 25,302 bytes from gzip. The embedded data block ends at `0x5b977` without compression and at -`0x46e28` with it, freeing ~83 KB of the 512 KB image. +`0x462d6` with it, freeing ~86 KB of the 512 KB image. -Merging the JS files into one bundle is worth more than the minifier and -gzip combined: served per file, the 17 scripts gzip to 23,302 bytes; as -one `main.js` bundle they gzip to 16,948 bytes, because the gzip -dictionary spans all scripts and every page fetches the bundle only -once. +The consolidation helps at every step. The 17 scripts gzip to 23,302 +bytes as separate files but to 17,231 bytes as one `main.js` bundle, +because the gzip dictionary spans all of them. The single-page layout +then removes the per-page HTML and, more importantly, the repeated +downloads: with the multi-page UI the browser fetched `main.js` on every +navigation; the SPA fetches everything once and section switches are +pure in-page JavaScript (measured on a real device: cold load ~450 ms, +section switch ~60-160 ms, the only network traffic afterwards is the +JSON polling of the visible section). ## Notes - The files stay well below the `uint16_t` size limit of the file table - (largest gzip output: 16.9 KB for the merged `main.js`). + (largest gzip output: 17.2 KB for the merged `main.js`). - `fileadder` terminates the embedded files with a NUL directly after the content (previously at `data_read + 1`), so the `strlen()`-based size computation no longer depends on uninitialised buffer content.