Files
silo-server/internal/server/frontend.go
T

50 lines
1.4 KiB
Go

package server
import (
"io/fs"
"net/http"
"strings"
)
// WebDistFS holds the embedded frontend build output.
// When nil, FrontendHandler returns a placeholder response.
var WebDistFS fs.FS
// FrontendHandler returns an http.Handler that serves the embedded SPA.
// It serves static files from WebDistFS and falls back to index.html for
// SPA routing (any path that doesn't match a file).
func FrontendHandler() http.Handler {
if WebDistFS == nil {
return http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte("Frontend not built. Run: cd web && bun run build"))
})
}
fileServer := http.FileServer(http.FS(WebDistFS))
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
path := r.URL.Path
// Try to serve the file directly
if path != "/" && !strings.HasSuffix(path, "/") {
if f, err := WebDistFS.Open(strings.TrimPrefix(path, "/")); err == nil {
f.Close()
fileServer.ServeHTTP(w, r)
return
}
}
// SPA fallback: serve index.html
indexBytes, err := fs.ReadFile(WebDistFS, "index.html")
if err != nil {
http.Error(w, "index.html not found", http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "text/html; charset=utf-8")
w.WriteHeader(http.StatusOK)
_, _ = w.Write(indexBytes)
})
}