From fa3b0db243e116fba1b477d4e5034fd2c26270b5 Mon Sep 17 00:00:00 2001 From: rcourtman Date: Thu, 6 Nov 2025 13:54:26 +0000 Subject: [PATCH] Improve static asset caching for hashed files Hashed static assets (e.g., index-BXHytNQV.js, index-TvhSzimt.css) are now cached for 1 year with immutable flag since content hash changes when files change. Benefits: - Faster page loads on subsequent visits - Reduced server bandwidth - Better user experience on demo and production instances Only index.html and non-hashed assets remain uncached to ensure users always get the latest version. --- internal/api/frontend_embed.go | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/internal/api/frontend_embed.go b/internal/api/frontend_embed.go index bb53429..6dfcc63 100644 --- a/internal/api/frontend_embed.go +++ b/internal/api/frontend_embed.go @@ -138,16 +138,18 @@ func serveFrontendHandler() http.HandlerFunc { if err == nil { // Detect content type contentType := "application/octet-stream" + isImmutable := false + if strings.HasSuffix(lookupPath, ".html") { contentType = "text/html; charset=utf-8" } else if strings.HasSuffix(lookupPath, ".css") { contentType = "text/css; charset=utf-8" + // CSS files with hashes are immutable (e.g., index-abc123.css) + isImmutable = strings.Contains(lookupPath, "-") && strings.Contains(lookupPath, ".css") } else if strings.HasSuffix(lookupPath, ".js") { contentType = "application/javascript; charset=utf-8" - // Add cache-busting headers for JS files to force reload - w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate") - w.Header().Set("Pragma", "no-cache") - w.Header().Set("Expires", "0") + // JS files with hashes are immutable (e.g., index-BXHytNQV.js) + isImmutable = strings.Contains(lookupPath, "-") && strings.Contains(lookupPath, ".js") } else if strings.HasSuffix(lookupPath, ".json") { contentType = "application/json" } else if strings.HasSuffix(lookupPath, ".svg") { @@ -155,6 +157,17 @@ func serveFrontendHandler() http.HandlerFunc { } w.Header().Set("Content-Type", contentType) + + // Hashed assets are immutable - cache aggressively + // Non-hashed assets should not be cached + if isImmutable { + w.Header().Set("Cache-Control", "public, max-age=31536000, immutable") + } else { + w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate") + w.Header().Set("Pragma", "no-cache") + w.Header().Set("Expires", "0") + } + w.Write(content) return }