92 lines
2.2 KiB
Go
92 lines
2.2 KiB
Go
// backend\frontend.go
|
||
|
||
package main
|
||
|
||
import (
|
||
"embed"
|
||
"fmt"
|
||
"io/fs"
|
||
"net/http"
|
||
"path"
|
||
"strings"
|
||
)
|
||
|
||
// Vite-Build einbetten.
|
||
// Beim Go-Build muss backend/web/dist bereits existieren.
|
||
//
|
||
//go:embed web/dist web/dist/*
|
||
var embeddedFrontend embed.FS
|
||
|
||
func makeFrontendHandler() (http.Handler, bool) {
|
||
distFS, err := fs.Sub(embeddedFrontend, "web/dist")
|
||
if err != nil {
|
||
fmt.Println("⚠️ Frontend dist nicht im Binary gefunden – API läuft trotzdem:", err)
|
||
return nil, false
|
||
}
|
||
|
||
// Prüfen, ob index.html vorhanden ist
|
||
if _, err := fs.Stat(distFS, "index.html"); err != nil {
|
||
fmt.Println("⚠️ Frontend index.html nicht im Binary gefunden – API läuft trotzdem:", err)
|
||
return nil, false
|
||
}
|
||
|
||
fileServer := http.FileServer(http.FS(distFS))
|
||
|
||
h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||
// /api bleibt API
|
||
if strings.HasPrefix(r.URL.Path, "/api/") {
|
||
http.NotFound(w, r)
|
||
return
|
||
}
|
||
|
||
reqPath := r.URL.Path
|
||
if reqPath == "" || reqPath == "/" {
|
||
w.Header().Set("Cache-Control", "no-store")
|
||
indexBytes, err := fs.ReadFile(distFS, "index.html")
|
||
if err != nil {
|
||
http.Error(w, "index.html nicht gefunden", http.StatusInternalServerError)
|
||
return
|
||
}
|
||
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||
_, _ = w.Write(indexBytes)
|
||
return
|
||
}
|
||
|
||
// URL-Pfad bereinigen
|
||
clean := path.Clean("/" + reqPath)
|
||
rel := strings.TrimPrefix(clean, "/")
|
||
|
||
// Wenn echte Datei im embedded FS existiert -> ausliefern
|
||
if fi, err := fs.Stat(distFS, rel); err == nil && !fi.IsDir() {
|
||
ext := strings.ToLower(path.Ext(rel))
|
||
if ext != "" && ext != ".html" {
|
||
w.Header().Set("Cache-Control", "public, max-age=31536000, immutable")
|
||
} else {
|
||
w.Header().Set("Cache-Control", "no-store")
|
||
}
|
||
fileServer.ServeHTTP(w, r)
|
||
return
|
||
}
|
||
|
||
// SPA-Fallback
|
||
w.Header().Set("Cache-Control", "no-store")
|
||
indexBytes, err := fs.ReadFile(distFS, "index.html")
|
||
if err != nil {
|
||
http.Error(w, "index.html nicht gefunden", http.StatusInternalServerError)
|
||
return
|
||
}
|
||
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||
_, _ = w.Write(indexBytes)
|
||
})
|
||
|
||
return h, true
|
||
}
|
||
|
||
func registerFrontend(mux *http.ServeMux) {
|
||
h, ok := makeFrontendHandler()
|
||
if !ok {
|
||
return
|
||
}
|
||
mux.Handle("/", h)
|
||
}
|