50 lines
1.4 KiB
Go
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)
|
|
})
|
|
}
|