From d43e34405209d5db2d062d7477230afb11020f84 Mon Sep 17 00:00:00 2001 From: jessikitty Date: Wed, 19 Aug 2026 16:48:55 +1000 Subject: [PATCH] =?UTF-8?q?fix:=20cache=20policy=20=E2=80=94=20app=20JS/HT?= =?UTF-8?q?ML=20revalidate=20each=20load=20(stale=20ES=20module=20imports?= =?UTF-8?q?=20survived=20deploys),=20OpenCV.js=20WASM=20cached=20immutably?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/server.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/server/server.js b/server/server.js index 89c4782..6aec75a 100644 --- a/server/server.js +++ b/server/server.js @@ -19,6 +19,21 @@ const MODE = process.env.EXHIBIT_MODE || 'dev'; const app = express(); app.use(express.json({ limit: '20mb' })); // base64 asset uploads +/* ---------- cache policy ---------- + * ES modules are fetched under their own URLs, so a cache-busting query on the + * entry point does nothing for its imports — a stale detect.js or solve-cv.js + * silently keeps running after a deploy. App code and HTML therefore revalidate + * every load (ETag makes that a cheap 304), while the 13MB OpenCV.js WASM is + * cached hard: it only changes when its pinned version does. */ +app.use((req, res, next) => { + if (req.path === '/vendor/opencv.js') { + res.setHeader('Cache-Control', 'public, max-age=31536000, immutable'); + } else if (/\.(js|html)$/.test(req.path) || req.path === '/') { + res.setHeader('Cache-Control', 'no-cache'); + } + next(); +}); + // ---------- public static ---------- app.use(express.static(path.join(__dirname, '..', 'public'))); app.use('/data/ghosts.json', express.static(path.join(__dirname, '..', 'data', 'ghosts.json')));