package spahandler import ( "fmt" "io/fs" "net/http" "os" "path/filepath" "text/template" "github.com/olivere/vite" "github.com/rs/zerolog/log" "xtablo-backend/internal/frontend" ) type handler struct { distFS fs.FS } func NewHandler() *handler { distFS, err := fs.Sub(frontend.DistFS, "dist") if err != nil { panic(fmt.Errorf("creating sub-filesystem for 'dist' directory: %w", err)) } return &handler{ distFS: distFS, } } func (h *handler) GetAssets() http.HandlerFunc { return http.FileServerFS(h.distFS).ServeHTTP } func (h *handler) GetSpa() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var err error defer func() { if err != nil { log.Err(err).Msg(err.Error()) } }() if r.URL.Path == "/" || r.URL.Path == "/index.html" { viteFragment, err := vite.HTMLFragment(vite.Config{ FS: h.distFS, IsDev: false, }) if err != nil { log.Err(err).Msg(err.Error()) http.Error(w, "Error instantiating vite fragment", http.StatusInternalServerError) return } tmpl, err := template.New("index").Parse(indexTmpl) if err != nil { http.Error(w, "Error parsing template", http.StatusInternalServerError) return } if err = tmpl.Execute(w, map[string]interface{}{ "Vite": viteFragment, }); err != nil { http.Error(w, "Error executing template", http.StatusInternalServerError) return } return } // Serve the public files generated by Vite. By default, these files are // referenced in the DOM with a root-relative URL format (e.g. '/file.ext'). http.ServeFileFS(w, r, h.distFS, filepath.Base(r.URL.Path)) } } func (h *handler) GetDevSpa() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var err error defer func() { if err != nil { log.Err(err).Msg(err.Error()) } }() if r.URL.Path == "/" || r.URL.Path == "/index.html" { viteFragment, err := vite.HTMLFragment(vite.Config{ FS: os.DirFS("ui"), IsDev: true, ViteURL: "http://localhost:5173", ViteTemplate: vite.SvelteTs, ViteEntry: "/src/main.ts", }) if err != nil { http.Error(w, "Error instantiating vite fragment", http.StatusInternalServerError) return } tmpl, err := template.New("index").Parse(indexTmpl) if err != nil { http.Error(w, "Error parsing template", http.StatusInternalServerError) return } if err = tmpl.Execute(w, map[string]interface{}{ "Vite": viteFragment, }); err != nil { http.Error(w, "Error executing template", http.StatusInternalServerError) return } return } // Serve files in the public directory. By default, these files are // referenced in the DOM with a root-relative URL format (e.g. '/file.ext'). http.ServeFileFS(w, r, os.DirFS("./public"), filepath.Base(r.URL.Path)) } } var indexTmpl = ` {{ .Vite.Tags }}
`