From 096455944e979a644f16aafd762c54c86049d003 Mon Sep 17 00:00:00 2001 From: Jared Knowles Date: Tue, 11 Aug 2026 10:37:27 -0400 Subject: [PATCH] fix(nginx): cache and compress the duckdb-wasm asset The wasm engine is the single largest asset in the build (39,362,651 bytes) but the immutable-cache location regex did not include `wasm`, so on the Docker/nginx path it got no Cache-Control at all, and no gzip directive existed anywhere -- nginx's default gzip_types is text/html only, so it shipped uncompressed on every cold load. Verified against nginx:alpine (1.31.3) with the real dist/ mounted: `nginx -t` passes, and the wasm now returns Content-Type: application/wasm, Content-Encoding: gzip, Cache-Control: public, max-age=31536000, immutable -- 8,766,496 bytes on the wire instead of 39,362,651. Dynamic gzip rather than gzip_static because the Vite build emits no pre-compressed .gz files. --- nginx.conf | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/nginx.conf b/nginx.conf index db46074..2ae06bd 100644 --- a/nginx.conf +++ b/nginx.conf @@ -37,12 +37,32 @@ server { root /usr/share/nginx/html/crdc-demo/; # Adjust if base is different index index.html; + # Compress text assets and — most importantly — the duckdb-wasm engine, + # which is ~39MB uncompressed and ~8.8MB gzipped. Without this it ships + # uncompressed on every cold load. Dynamic gzip rather than gzip_static + # because the Vite build emits no pre-compressed .gz files. + gzip on; + gzip_vary on; + gzip_min_length 1024; + gzip_proxied any; + gzip_comp_level 6; + gzip_types + text/plain + text/css + application/javascript + text/javascript + application/json + image/svg+xml + application/wasm; + location / { try_files $uri $uri/ /index.html; } - # Civilytics design tokens: immutable cache headers for static assets - location ~* \.(js|css|png|jpg|jpeg|gif|svg|woff2|ttf)$ { + # Civilytics design tokens: immutable cache headers for static assets. + # `wasm` belongs here too — the duckdb engine is content-hashed by Vite and + # is by far the largest asset in the build, so it must not be re-fetched. + location ~* \.(js|css|wasm|png|jpg|jpeg|gif|svg|woff2|ttf)$ { expires 1y; add_header Cache-Control "public, max-age=31536000, immutable"; try_files $uri =404;