4d4e07eb2e
- 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
48 lines
1.3 KiB
Go
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))
|
|
}
|
|
})
|
|
}
|