fix(dev-deploy): explicit Cache-Control on the UI surface #18

Merged
developer merged 1 commits from feature/caddy-cache-headers into development 2026-05-19 08:11:40 +00:00
Owner

Summary

  • Without explicit headers, Caddy's file_server falls back to heuristic caching (Last-Modified based), which leaves stale index.html + chunks cached for minutes-to-hours on the long-lived dev environment. On Safari that combines with stale conditional requests into a visible multi-second freeze on reload.
  • Standard SvelteKit cache split:
    • _app/immutable/*public, max-age=31536000, immutable (hash-named, safe forever)
    • everything else → no-cache, must-revalidate (always revalidate; fresh deploy lands on next reload)
  • Mirrored in both Caddyfile.dev and Caddyfile.prod so prod gets the same policy when prod-deploy plumbing arrives.

Test plan

  • caddy validate clean on both files
  • docker smoke-test: /_app/immutable/x.js → immutable header; /env.js and /some/route (SPA-fallback) → no-cache header
  • Manual on dev-deploy after merge: reload https://www.galaxy.lan in Safari (non-private window) — should not freeze even with warm cache
## Summary - Without explicit headers, Caddy's `file_server` falls back to heuristic caching (Last-Modified based), which leaves stale `index.html` + chunks cached for minutes-to-hours on the long-lived dev environment. On Safari that combines with stale conditional requests into a visible multi-second freeze on reload. - Standard SvelteKit cache split: - `_app/immutable/*` → `public, max-age=31536000, immutable` (hash-named, safe forever) - everything else → `no-cache, must-revalidate` (always revalidate; fresh deploy lands on next reload) - Mirrored in both `Caddyfile.dev` and `Caddyfile.prod` so prod gets the same policy when prod-deploy plumbing arrives. ## Test plan - [x] `caddy validate` clean on both files - [x] docker smoke-test: `/_app/immutable/x.js` → immutable header; `/env.js` and `/some/route` (SPA-fallback) → no-cache header - [ ] Manual on dev-deploy after merge: reload `https://www.galaxy.lan` in Safari (non-private window) — should not freeze even with warm cache
developer added 1 commit 2026-05-19 08:11:37 +00:00
Caddy's `file_server` did not set Cache-Control on the SvelteKit
build, so browsers fell back to heuristic caching keyed off
Last-Modified. On the long-lived dev environment the heuristic
window leaves the previous deploy's `index.html` cached for
minutes-to-hours, and Safari combined that with stale conditional
requests into a visible multi-second freeze on every reload (the
reproduction was "private window reloads instantly, normal window
hangs; clearing Safari caches restores normal speed"). Push
delivery itself works — heartbeat keeps the SubscribeEvents stream
alive — but the bundle path stalls behind the browser revalidating
a chain of stale chunks.

Mirror the standard SvelteKit cache split inside both Caddyfiles:

- `_app/immutable/*` — hash-named JS/CSS chunks Vite emits with
  content-addressed file names — `Cache-Control:
  public, max-age=31536000, immutable`. Safe to cache forever
  because the name changes whenever the content does, so the next
  deploy serves new files under new URLs.
- Everything else (`index.html` fallback via `try_files`,
  `env.js`, `version.json`, `core.wasm`, `wasm_exec.js`,
  `favicon.svg`) — `Cache-Control: no-cache, must-revalidate`.
  The browser still uses the cached body when the ETag matches,
  but it always asks first; a fresh deploy reaches the user on
  the next reload without a manual cache clear.

Smoke-tested locally: a docker-run Caddy with this config returns
the immutable header only for `/_app/immutable/*` and the
no-cache header for `/index.html`, `/env.js`, and the SPA-fallback
path `/some/route`. The Caddyfile passes `caddy validate` in
both `Caddyfile.dev` and `Caddyfile.prod`; the pre-existing
formatting warning on line 7 is untouched.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
developer merged commit 08345606a5 into development 2026-05-19 08:11:40 +00:00
developer deleted branch feature/caddy-cache-headers 2026-05-19 08:11:40 +00:00
Sign in to join this conversation.