Compare commits

...

4 Commits

Author SHA1 Message Date
Eva Ho
fc1f10cd0b fix test 2025-12-16 13:28:15 -05:00
Eva Ho
0e02a037b4 clean up 2025-12-15 17:49:24 -05:00
Eva Ho
4c2c51761e adding test 2025-12-15 17:46:26 -05:00
Eva Ho
c02bf766fd fix: windows app blank ui issue 2025-12-15 17:19:26 -05:00
2 changed files with 60 additions and 2 deletions

View File

@@ -7,7 +7,9 @@ import (
"embed" "embed"
"errors" "errors"
"io/fs" "io/fs"
"mime"
"net/http" "net/http"
"path/filepath"
"strings" "strings"
"time" "time"
) )
@@ -15,6 +17,13 @@ import (
//go:embed app/dist //go:embed app/dist
var appFS embed.FS var appFS embed.FS
func init() {
mime.AddExtensionType(".js", "application/javascript; charset=utf-8")
mime.AddExtensionType(".css", "text/css; charset=utf-8")
mime.AddExtensionType(".woff2", "font/woff2")
mime.AddExtensionType(".svg", "image/svg+xml")
}
// appHandler returns an HTTP handler that serves the React SPA. // appHandler returns an HTTP handler that serves the React SPA.
// It tries to serve real files first, then falls back to index.html for React Router. // It tries to serve real files first, then falls back to index.html for React Router.
func (s *Server) appHandler() http.Handler { func (s *Server) appHandler() http.Handler {
@@ -24,11 +33,19 @@ func (s *Server) appHandler() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
p := strings.TrimPrefix(r.URL.Path, "/") p := strings.TrimPrefix(r.URL.Path, "/")
if _, err := fsys.Open(p); err == nil {
// Serve the file directly if file, err := fsys.Open(p); err == nil {
file.Close()
// Ensure proper Content-Type headers
if contentType := mime.TypeByExtension(filepath.Ext(p)); contentType != "" {
w.Header().Set("Content-Type", contentType)
}
fileServer.ServeHTTP(w, r) fileServer.ServeHTTP(w, r)
return return
} }
// Fallback serve index.html for unknown paths so React Router works // Fallback serve index.html for unknown paths so React Router works
data, err := fs.ReadFile(fsys, "index.html") data, err := fs.ReadFile(fsys, "index.html")
if err != nil { if err != nil {
@@ -39,6 +56,8 @@ func (s *Server) appHandler() http.Handler {
} }
return return
} }
w.Header().Set("Content-Type", "text/html; charset=utf-8")
http.ServeContent(w, r, "index.html", time.Time{}, bytes.NewReader(data)) http.ServeContent(w, r, "index.html", time.Time{}, bytes.NewReader(data))
}) })
} }

39
app/ui/app_test.go Normal file
View File

@@ -0,0 +1,39 @@
//go:build windows || darwin
package ui
import (
"io/fs"
"strings"
"testing"
)
// TestEmbeddedAssets verifies that the correct UI assets are embedded.
// This test will FAIL THE BUILD if wrong files are embedded.
func TestEmbeddedAssets(t *testing.T) {
fsys, err := fs.Sub(appFS, "app/dist")
if err != nil {
t.Fatal("app/dist not found in embedded filesystem - UI not built")
}
data, err := fs.ReadFile(fsys, "index.html")
if err != nil {
t.Fatal("index.html not found - run 'go generate' first")
}
html := string(data)
if strings.Contains(html, "/src/main.tsx") {
t.Fatal("Wrong index.html embedded: has /src/main.tsx (dev paths). The UI was not built. Run 'npm run build' first.")
}
if !strings.Contains(html, "/assets/index-") {
t.Fatal("Wrong index.html embedded: missing /assets/index-* (production paths). The UI was not built correctly.")
}
if _, err := fsys.Open("assets"); err != nil {
t.Fatal("assets/ directory not found - UI build incomplete")
}
t.Log("Embedded assets verified - UI built correctly")
}