Files
mathiasandClaude Opus 4.8 fa9f101abe feat(deploy): add Dockerfile and vendor htmx for deployable image
Stage-0 web UI needs a self-contained container image. Two changes:

- Dockerfile: multi-stage build (golang:1.25 builder, CGO off + static
  link, -trimpath -s -w) into distroless static nonroot. The committed
  templ output and vendored asset mean a plain `go build` suffices — no
  codegen or CDN at build/run time. Existing .gitea CI already builds and
  pushes localhost:5000/tapir:<sha> + mirrors to GitHub (deploy patch
  intentionally omitted — cutover is held), so it only needed this file.

- Vendor htmx 1.9.12 locally (internal/web/static/, embed.FS, served at
  /static/ outside the auth guard) and point Layout at /static/htmx.min.js
  instead of unpkg. The deployed UI must not depend on an external CDN
  being reachable from the cluster.

task check green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 00:08:35 +02:00

25 lines
779 B
Go

package web
import (
"embed"
"net/http"
)
// staticFS holds the vendored client assets (htmx) served under /static/. They
// are embedded into the binary so a deployed image works without any external
// CDN — the UI must not depend on unpkg being reachable from the cluster.
//
//go:embed static/*
var staticFS embed.FS
// staticHandler serves the embedded assets with a long cache lifetime. The
// files are content-stable (versioned by filename, e.g. htmx.min.js pinned to a
// release), so aggressive caching is safe.
func staticHandler() http.Handler {
fs := http.FileServer(http.FS(staticFS))
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Cache-Control", "public, max-age=31536000, immutable")
fs.ServeHTTP(w, r)
})
}