ai cooking
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge pull request #220 from paulgmiller/pmiller/brokehtmx

Turns out our cache for tailwind was bad.

authored by

Paul Miller and committed by
GitHub
10a5dfe3 288defd9

+21 -19
+7 -10
cmd/careme/web.go
··· 56 56 return fmt.Errorf("failed to create recipe generator: %w", err) 57 57 } 58 58 59 - //using etags for caching because this changes somewhat often 60 - tailwindETag := fmt.Sprintf(`"%x"`, sha256.Sum256(tailwindCSS)) 61 - mux.HandleFunc("/static/tailwind.css", func(w http.ResponseWriter, r *http.Request) { 62 - if r.Header.Get("If-None-Match") == tailwindETag { 63 - w.WriteHeader(http.StatusNotModified) 64 - return 65 - } 59 + //make filename use hash to force cach invalidation (etag really failed here) 60 + tailwindHash := fmt.Sprintf("%x", sha256.Sum256(tailwindCSS)) 61 + tailwindAssetPath := fmt.Sprintf("/static/tailwind.%s.css", tailwindHash[:12]) 62 + templates.SetTailwindAssetPath(tailwindAssetPath) 63 + mux.HandleFunc(tailwindAssetPath, func(w http.ResponseWriter, r *http.Request) { 66 64 w.Header().Set("Content-Type", "text/css; charset=utf-8") 67 - w.Header().Set("Cache-Control", "public, max-age=0, no-cache") 68 - w.Header().Set("ETag", tailwindETag) 65 + w.Header().Set("Cache-Control", "public, max-age=31536000, immutable") 69 66 if _, err := w.Write(tailwindCSS); err != nil { 70 67 slog.ErrorContext(r.Context(), "failed to write tailwind css", "error", err) 71 68 } ··· 74 71 //intentionally versioned so that we can cache aggressively 75 72 mux.HandleFunc("/static/htmx@2.0.8.js", func(w http.ResponseWriter, r *http.Request) { 76 73 w.Header().Set("Content-Type", "application/javascript; charset=utf-8") 77 - w.Header().Set("Cache-Control", "public, immutable") 74 + w.Header().Set("Cache-Control", "public, max-age=31536000, immutable") 78 75 if _, err := w.Write(htmx208JS); err != nil { 79 76 slog.ErrorContext(r.Context(), "failed to write htmx js", "error", err) 80 77 }
+1 -1
deploy/deploy.yaml
··· 21 21 runAsGroup: 65532 22 22 containers: 23 23 - name: careme 24 - image: ghcr.io/paulgmiller/careme:a4aae54 # was 3ef7ea6 24 + image: ghcr.io/paulgmiller/careme:d838f8a # was 3ef7ea6 25 25 imagePullPolicy: IfNotPresent 26 26 ports: 27 27 - containerPort: 8080
-3
internal/locations/locations.go
··· 16 16 "sync" 17 17 ) 18 18 19 - const htmxPageCSP = "default-src 'self'; script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; object-src 'none'; base-uri 'self'" 20 - 21 19 type krogerClient interface { 22 20 LocationListWithResponse(ctx context.Context, params *kroger.LocationListParams, reqEditors ...kroger.RequestEditorFn) (*kroger.LocationListResponse, error) 23 21 // LocationDetailsWithResponse request ··· 160 158 if currentUser != nil { 161 159 favoriteStore = currentUser.FavoriteStore 162 160 } 163 - w.Header().Set("Content-Security-Policy", htmxPageCSP) 164 161 if err := l.renderLocationsPage(w, ctx, zip, favoriteStore, currentUser != nil); err != nil { 165 162 slog.ErrorContext(ctx, "failed to render locations page", "zip", zip, "error", err) 166 163 http.Error(w, "template error", http.StatusInternalServerError)
-4
internal/recipes/server.go
··· 26 26 "github.com/samber/lo" 27 27 ) 28 28 29 - const htmxPageCSP = "default-src 'self'; script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; object-src 'none'; base-uri 'self'" 30 - 31 29 type locServer interface { 32 30 GetLocationByID(ctx context.Context, locationID string) (*locations.Location, error) 33 31 } ··· 74 72 75 73 func (s *server) handleSingle(w http.ResponseWriter, r *http.Request) { 76 74 ctx := r.Context() 77 - 78 75 hash := r.PathValue("hash") 79 76 if hash == "" { 80 77 http.Error(w, "missing recipe hash", http.StatusBadRequest) 81 78 return 82 79 } 83 80 84 - w.Header().Set("Content-Security-Policy", htmxPageCSP) 85 81 recipe, err := s.SingleFromCache(ctx, hash) 86 82 if err != nil { 87 83 http.Error(w, "recipe not found", http.StatusNotFound)
+1 -1
internal/templates/tailwind_head.html
··· 13 13 --brand-900: {{.Colors.C900}}; 14 14 } 15 15 </style> 16 - <link rel="stylesheet" href="/static/tailwind.css"> 16 + <link rel="stylesheet" href="{{TailwindAssetPath}}"> 17 17 {{end}}
+12
internal/templates/templates.go
··· 23 23 funcs := template.FuncMap{ 24 24 "ClerkEnabled": ClerkEnabled, 25 25 "ClerkPublishableKey": ClerkPublishableKey, 26 + "TailwindAssetPath": TailwindAssetPath, 26 27 } 27 28 tmpls, err := template.New("all").Funcs(funcs).ParseFS(htmlFiles, "*.html") 28 29 if err != nil { ··· 51 52 // basically a hack for us till we make this non global 52 53 func SetClarity(project string) { 53 54 clarityproject = project 55 + } 56 + 57 + // SetTailwindAssetPath sets the served Tailwind path used by templates. 58 + func SetTailwindAssetPath(path string) { 59 + tailwindAssetPath = path 54 60 } 55 61 56 62 var clarityproject string 57 63 var clerkPublishableKey string 64 + var tailwindAssetPath = "/static/tailwind.css" 58 65 59 66 // ClarityScript generates the Microsoft Clarity tracking script HTML 60 67 func ClarityScript() template.HTML { ··· 82 89 func ClerkPublishableKey() string { 83 90 return clerkPublishableKey 84 91 } 92 + 93 + // TailwindAssetPath returns the served Tailwind stylesheet URL. 94 + func TailwindAssetPath() string { 95 + return tailwindAssetPath 96 + }