mirror of
https://github.com/ThisTine/Snip.git
synced 2026-08-18 23:18:47 +07:00
60 lines
1.4 KiB
Go
60 lines
1.4 KiB
Go
// Package frontend serves the built SPA. It owns exactly the app routes
|
|
// (/, /login, /dashboard) plus static assets; everything else is 404 here and
|
|
// handled by the redirect command in production.
|
|
package frontend
|
|
|
|
import (
|
|
"net/http"
|
|
"os"
|
|
"path"
|
|
"path/filepath"
|
|
)
|
|
|
|
type Server struct {
|
|
dist string
|
|
fs http.Handler
|
|
spa map[string]bool
|
|
indexAbs string
|
|
}
|
|
|
|
func New(dist string) *Server {
|
|
return &Server{
|
|
dist: dist,
|
|
fs: http.FileServer(http.Dir(dist)),
|
|
spa: map[string]bool{"/": true, "/login": true, "/dashboard": true},
|
|
indexAbs: filepath.Join(dist, "index.html"),
|
|
}
|
|
}
|
|
|
|
func (s *Server) Handler() http.Handler {
|
|
mux := http.NewServeMux()
|
|
mux.HandleFunc("/healthz", func(w http.ResponseWriter, _ *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
_, _ = w.Write([]byte(`{"status":"ok"}`))
|
|
})
|
|
mux.HandleFunc("/", s.serve)
|
|
return mux
|
|
}
|
|
|
|
func (s *Server) serve(w http.ResponseWriter, r *http.Request) {
|
|
clean := path.Clean(r.URL.Path)
|
|
|
|
// App routes always render the SPA shell.
|
|
if s.spa[clean] {
|
|
http.ServeFile(w, r, s.indexAbs)
|
|
return
|
|
}
|
|
|
|
// Real static file (assets, favicon, …)?
|
|
if clean != "/" {
|
|
full := filepath.Join(s.dist, filepath.FromSlash(clean))
|
|
if st, err := os.Stat(full); err == nil && !st.IsDir() {
|
|
s.fs.ServeHTTP(w, r)
|
|
return
|
|
}
|
|
}
|
|
|
|
// Unknown path: not this command's concern.
|
|
http.NotFound(w, r)
|
|
}
|