Files
tiny-forge/internal/api/static.go
T
alexei.dolgolyov 4d4e07eb2e fix: serve SvelteKit _app assets correctly
- Use all: prefix in go:embed to include _app/ directory (Go skips
  _-prefixed dirs by default)
- Move jsonContentType middleware to /api route group only
- Use http.ServeContent for proper MIME type detection
- Remove unused fileServer variable
2026-03-28 13:34:02 +03:00

48 lines
1.3 KiB
Go

package api
import (
"io"
"io/fs"
"net/http"
"strings"
)
// StaticHandler serves embedded SPA files with fallback to index.html
// for all non-API routes (SPA client-side routing support).
func StaticHandler(webFS fs.FS) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Skip API routes — they are handled by the API router.
if strings.HasPrefix(r.URL.Path, "/api") {
http.NotFound(w, r)
return
}
// Try to serve the exact file from the embedded FS.
path := strings.TrimPrefix(r.URL.Path, "/")
if path == "" {
path = "index.html"
}
// Check if file exists in the embedded FS.
if f, err := webFS.Open(path); err == nil {
stat, statErr := f.Stat()
f.Close()
if statErr == nil && !stat.IsDir() {
// Serve the actual file. Use http.ServeContent for correct MIME detection.
file, _ := webFS.Open(path)
defer file.Close()
http.ServeContent(w, r, stat.Name(), stat.ModTime(), file.(io.ReadSeeker))
return
}
}
// File not found: serve index.html for SPA client-side routing.
indexFile, _ := webFS.Open("index.html")
if indexFile != nil {
defer indexFile.Close()
stat, _ := indexFile.Stat()
http.ServeContent(w, r, "index.html", stat.ModTime(), indexFile.(io.ReadSeeker))
}
})
}