38 lines
994 B
Go
38 lines
994 B
Go
package httpserver
|
|
|
|
import (
|
|
"io/fs"
|
|
"net/http"
|
|
)
|
|
|
|
// spaHandler serves the embedded Vue SPA out of distFS (already rooted at
|
|
// web/dist, i.e. index.html is at its top level). Any request path that
|
|
// doesn't match a real file falls back to index.html so client-side routes
|
|
// (deep links) resolve correctly.
|
|
func spaHandler(distFS fs.FS) http.HandlerFunc {
|
|
fileServer := http.FileServer(http.FS(distFS))
|
|
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
upath := r.URL.Path
|
|
if upath == "" || upath == "/" {
|
|
upath = "index.html"
|
|
} else {
|
|
upath = upath[1:] // strip leading slash for fs.Stat
|
|
}
|
|
|
|
if _, err := fs.Stat(distFS, upath); err != nil {
|
|
r = cloneWithPath(r, "/")
|
|
}
|
|
|
|
fileServer.ServeHTTP(w, r)
|
|
}
|
|
}
|
|
|
|
// cloneWithPath returns a shallow copy of r with URL.Path replaced, so the
|
|
// original request (and its URL) is left untouched.
|
|
func cloneWithPath(r *http.Request, path string) *http.Request {
|
|
r2 := r.Clone(r.Context())
|
|
r2.URL.Path = path
|
|
return r2
|
|
}
|