From 839d842fd1dcd852344cd2bf48ba11a4c2c2000b Mon Sep 17 00:00:00 2001 From: Bryan Frimin Date: Thu, 24 Apr 2025 17:57:59 -0700 Subject: [PATCH] Cache static assets Signed-off-by: Bryan Frimin --- CHANGELOG.md | 1 + pkg/server/web/web.go | 69 ++++++++++++++++++++++++++----------------- 2 files changed, 43 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5dc91dc4b..ea5b0e9a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ All notable changes to this project will be documented in this file. ### Added - Risk can have note +- Cache static assets ## [0.13.2] - 2025-04-24 diff --git a/pkg/server/web/web.go b/pkg/server/web/web.go index afed31021..f2fea13a3 100644 --- a/pkg/server/web/web.go +++ b/pkg/server/web/web.go @@ -17,12 +17,15 @@ package web import ( "io/fs" "net/http" + "strings" + "time" "github.com/getprobo/probo/apps/console" ) type Server struct { - spaFS http.FileSystem + spaFS http.FileSystem + indexContent []byte } func NewServer() (*Server, error) { @@ -31,49 +34,61 @@ func NewServer() (*Server, error) { return nil, err } + indexFile, err := subFS.Open("index.html") + if err != nil { + return nil, err + } + defer indexFile.Close() + + stat, err := indexFile.Stat() + if err != nil { + return nil, err + } + + indexContent := make([]byte, stat.Size()) + _, err = indexFile.Read(indexContent) + if err != nil { + return nil, err + } + return &Server{ - spaFS: http.FS(subFS), + spaFS: http.FS(subFS), + indexContent: indexContent, }, nil } func (s *Server) ServeSPA(w http.ResponseWriter, r *http.Request) { path := r.URL.Path - if path == "/" { - path = "/index.html" - } - f, err := s.spaFS.Open(path) if err == nil { defer f.Close() + if isStaticFile(path) { + w.Header().Set("Cache-Control", "public, max-age=31536000") + w.Header().Set("Expires", time.Now().Add(365*24*time.Hour).Format(time.RFC1123)) + } + http.FileServer(s.spaFS).ServeHTTP(w, r) return } - indexFile, err := s.spaFS.Open("/index.html") - if err != nil { - http.Error(w, "Not Found", http.StatusNotFound) - return - } - defer indexFile.Close() - - stat, err := indexFile.Stat() - if err != nil { - http.Error(w, "Internal Server Error", http.StatusInternalServerError) - return - } - - content := make([]byte, stat.Size()) - _, err = indexFile.Read(content) - if err != nil { - http.Error(w, "Internal Server Error", http.StatusInternalServerError) - return - } - + w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate") + w.Header().Set("Pragma", "no-cache") + w.Header().Set("Expires", "0") w.Header().Set("Content-Type", "text/html; charset=utf-8") w.WriteHeader(http.StatusOK) - w.Write(content) + w.Write(s.indexContent) +} + +func isStaticFile(path string) bool { + extensions := []string{".js", ".css", ".png", ".jpg", ".jpeg", ".gif", ".svg", ".ico", ".woff", ".woff2", ".ttf", ".eot"} + for _, ext := range extensions { + if strings.HasSuffix(path, ext) { + return true + } + } + return false } func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {