Skip to content

feat(collab): immutable cache headers on content-hashed static assets#44

Merged
hblanken merged 1 commit into
collabfrom
feat/collab-static-cache-headers
Jun 14, 2026
Merged

feat(collab): immutable cache headers on content-hashed static assets#44
hblanken merged 1 commit into
collabfrom
feat/collab-static-cache-headers

Conversation

@hblanken

Copy link
Copy Markdown

Speed win V4 (PR 5 of 5) — repeat-visit + SPA-reload polish.

What

The collab SPA's hashed assets (Vite emits /assets/* and <name>-<hash>.<ext>) were served with the upstream UI route's default cache headers, so every reload re-fetched them.

collabMiddleware now stamps Cache-Control: public, max-age=31536000, immutable on GET responses for content-hashed assets:

  • matched by the /assets/ prefix or a -<hash>.<ext> filename pattern across the usual static extensions (js/css/fonts/images/wasm/map)
  • added only on 2xx (never cache a 404)
  • added only in the collab middleware — upstream opencode's own asset serving is untouched

index.html and other un-hashed paths are deliberately excluded, so a deploy's fresh asset manifest is always picked up — the hashed filenames guarantee cache-busting on content change.

Uses HttpServerResponse.setHeader, the same API the existing compression / fence / cors-vary middlewares use.

Files

  • server/server.tsisHashedStaticAsset() matcher + header stamp in collabMiddleware

Test plan

  • Deploy off this branch
  • Load /collab/new, open DevTools → Network → reload
  • Hashed assets (/assets/index-XXXX.js, etc.) show Cache-Control: public, max-age=31536000, immutable and serve from disk cache on reload
  • index.html (the navigation request) is NOT immutable-cached — a fresh deploy's new asset hashes load without a hard refresh
  • A 404 for a bogus /assets/missing-1234abcd.js does NOT get the immutable header

🤖 Generated with Claude Code

Speed win V4 — repeat-visit + SPA-reload polish.  The collab SPA's
hashed assets (Vite emits /assets/* and <name>-<hash>.<ext>) were
served with whatever default cache headers the upstream UI route sets,
so every reload re-fetched them.

collabMiddleware now stamps `Cache-Control: public, max-age=31536000,
immutable` on GET responses for content-hashed assets — matched by the
/assets/ prefix OR a `-<hash>.<ext>` filename pattern across the usual
static extensions (js/css/fonts/images/wasm/map).  The header is added
only on 2xx (never cache a 404), and ONLY in the collab middleware so
upstream opencode's own asset serving is untouched.

index.html and other un-hashed paths are deliberately excluded, so a
deploy's fresh asset manifest is always picked up — the hashed
filenames guarantee cache-busting on content change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@hblanken hblanken merged commit 580b944 into collab Jun 14, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant