From 00e4cb7a7576ea2edcb1558f1687fab925d7ca7b Mon Sep 17 00:00:00 2001 From: Markus Unterwaditzer Date: Sat, 25 Apr 2026 16:46:50 +0200 Subject: [PATCH] Compress the web frontend using brotli MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We can save 10 kB of binary size by compressing the frontend using brotli on max settings instead of gzip. Any browser beyond 2017 will be able to handle this, and since the Tailwind upgrade we already require browsers from 2024. (see also #903) Also we can stop using whatever gzlip cli is on the system, node has some stuff builtin. Source for the claim we require chrome 2023/firefox 2024 baseline right now: https://tailwindcss.com/docs/compatibility Compression comparison: | codec | size (bytes) | vs gzip -9 | wire format | `Content-Encoding` | |---|---:|---:|---|---| | (uncompressed) | 171,833 | +210.6% | — | — | | gzip -9 | 55,313 | — | gzip | `gzip` | | pigz -9 | 55,436 | +0.2% | gzip | `gzip` | | brotli q=4 | 55,085 | -0.4% | brotli | `br` | | brotli q=6 | 51,518 | -6.9% | brotli | `br` | | brotli q=9 | 51,243 | -7.4% | brotli | `br` | | **pigz -11** (zopfli) | **53,340** | **-3.6%** (~2 KB) | **gzip** | `gzip` | | **brotli q=11** | **47,712** | **-13.7%** (~7.4 KB) | **brotli** | `br` | --- .github/workflows/main.yml | 2 +- daemon/src/server.rs | 4 ++-- daemon/web/package.json | 2 +- daemon/web/scripts/compress-index.js | 11 +++++++++++ 4 files changed, 15 insertions(+), 4 deletions(-) create mode 100644 daemon/web/scripts/compress-index.js diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 214bd19..988dc91 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -628,7 +628,7 @@ jobs: - name: Build rayhunter-daemon openapi docs run: | mkdir -p daemon/web/build - touch daemon/web/build/{favicon.png,index.html.gz,rayhunter_orca_only.png,rayhunter_text.png} + touch daemon/web/build/{favicon.png,index.html.br,rayhunter_orca_only.png,rayhunter_text.png} cargo run --bin gen_api --features apidocs -- ./rayhunter-openapi.json - name: Make swagger folder run: | diff --git a/daemon/src/server.rs b/daemon/src/server.rs index b442238..199c75e 100644 --- a/daemon/src/server.rs +++ b/daemon/src/server.rs @@ -112,9 +112,9 @@ pub async fn serve_static( "index.html" => ( [ (header::CONTENT_TYPE, HeaderValue::from_static("text/html")), - (header::CONTENT_ENCODING, HeaderValue::from_static("gzip")), + (header::CONTENT_ENCODING, HeaderValue::from_static("br")), ], - include_bytes!("../web/build/index.html.gz"), + include_bytes!("../web/build/index.html.br"), ) .into_response(), path => { diff --git a/daemon/web/package.json b/daemon/web/package.json index 05d903a..28d3c55 100644 --- a/daemon/web/package.json +++ b/daemon/web/package.json @@ -4,7 +4,7 @@ "type": "module", "scripts": { "dev": "vite dev", - "build": "vite build && gzip -9 ./build/index.html", + "build": "vite build && node ./scripts/compress-index.js", "preview": "vite preview", "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", diff --git a/daemon/web/scripts/compress-index.js b/daemon/web/scripts/compress-index.js new file mode 100644 index 0000000..99e4200 --- /dev/null +++ b/daemon/web/scripts/compress-index.js @@ -0,0 +1,11 @@ +import { readFileSync, writeFileSync, unlinkSync } from 'node:fs'; +import { brotliCompressSync, constants } from 'node:zlib'; + +const input = './build/index.html'; +const output = './build/index.html.br'; + +const compressed = brotliCompressSync(readFileSync(input), { + params: { [constants.BROTLI_PARAM_QUALITY]: constants.BROTLI_MAX_QUALITY }, +}); +writeFileSync(output, compressed); +unlinkSync(input);