generated from CubeCraft-Creations/Tracehound
feat: embed React frontend in Go binary with SPA fallback
This commit is contained in:
@@ -3,7 +3,9 @@ package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"embed"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
@@ -22,6 +24,9 @@ import (
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
//go:embed all:src/dist
|
||||
var frontendFS embed.FS
|
||||
|
||||
// Config holds the application configuration.
|
||||
type Config struct {
|
||||
DBPath string `yaml:"db_path"`
|
||||
@@ -84,6 +89,9 @@ func main() {
|
||||
// API routes (auth required if API key is configured)
|
||||
r.Mount("/api/v1", auth.Middleware(cfg.APIKey)(apiRouter(sseHub, sqlDB)))
|
||||
|
||||
// Serve embedded React frontend with SPA fallback
|
||||
r.Mount("/", frontendHandler())
|
||||
|
||||
// Create server
|
||||
httpServer := &http.Server{
|
||||
Addr: ":" + cfg.Port,
|
||||
@@ -158,4 +166,37 @@ func loadConfig(path string) (*Config, error) {
|
||||
}
|
||||
|
||||
return &cfg, nil
|
||||
}
|
||||
|
||||
// frontendHandler returns an http.Handler that serves the embedded React
|
||||
// frontend from src/dist/ with SPA-style fallback: any path that doesn't
|
||||
// match a static file serves index.html for client-side routing.
|
||||
//
|
||||
// The frontend is embedded via //go:embed all:src/dist at build time.
|
||||
// If src/dist/ is empty or missing at build time, the embedded fallback
|
||||
// index.html (committed to the repo) is served instead, showing a
|
||||
// "run npm run build" message.
|
||||
func frontendHandler() http.Handler {
|
||||
distFS, err := fs.Sub(frontendFS, "src/dist")
|
||||
if err != nil {
|
||||
// Shouldn't happen if embed worked, but be defensive.
|
||||
panic("embedded frontend filesystem not found: " + err.Error())
|
||||
}
|
||||
|
||||
fileServer := http.FileServer(http.FS(distFS))
|
||||
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// Try to serve the requested file.
|
||||
f, err := distFS.Open(r.URL.Path[1:]) // strip leading "/"
|
||||
if err != nil {
|
||||
// File not found — serve index.html for SPA routing.
|
||||
r.URL.Path = "/"
|
||||
fileServer.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
f.Close()
|
||||
|
||||
// File exists, serve it.
|
||||
fileServer.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user