From c02bf766fd9b3fee0383cb978e7609775859e07f Mon Sep 17 00:00:00 2001 From: Eva Ho Date: Mon, 15 Dec 2025 17:19:19 -0500 Subject: [PATCH 1/4] fix: windows app blank ui issue --- app/ui/app.go | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/app/ui/app.go b/app/ui/app.go index d73df2c02..e359215ee 100644 --- a/app/ui/app.go +++ b/app/ui/app.go @@ -7,7 +7,9 @@ import ( "embed" "errors" "io/fs" + "mime" "net/http" + "path/filepath" "strings" "time" ) @@ -15,6 +17,13 @@ import ( //go:embed app/dist 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. // It tries to serve real files first, then falls back to index.html for React Router. 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) { 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) return } + // Fallback – serve index.html for unknown paths so React Router works data, err := fs.ReadFile(fsys, "index.html") if err != nil { @@ -39,6 +56,8 @@ func (s *Server) appHandler() http.Handler { } return } + + w.Header().Set("Content-Type", "text/html; charset=utf-8") http.ServeContent(w, r, "index.html", time.Time{}, bytes.NewReader(data)) }) } From 4c2c51761e8cb1be25f88eeeca8efbcb0efda57b Mon Sep 17 00:00:00 2001 From: Eva Ho Date: Mon, 15 Dec 2025 17:46:26 -0500 Subject: [PATCH 2/4] adding test --- app/ui/app_test.go | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 app/ui/app_test.go diff --git a/app/ui/app_test.go b/app/ui/app_test.go new file mode 100644 index 000000000..425ed4f88 --- /dev/null +++ b/app/ui/app_test.go @@ -0,0 +1,44 @@ +//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") + } + + // Check index.html exists + data, err := fs.ReadFile(fsys, "index.html") + if err != nil { + t.Fatal("index.html not found - run 'go generate' first") + } + + html := string(data) + + // Check it's NOT the source version + 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.") + } + + // Check it IS the built version + if !strings.Contains(html, "/assets/index-") { + t.Fatal("Wrong index.html embedded: missing /assets/index-* (production paths). The UI was not built correctly.") + } + + // Check assets directory exists + if _, err := fsys.Open("assets"); err != nil { + t.Fatal("assets/ directory not found - UI build incomplete") + } + + t.Log("Embedded assets verified - UI built correctly") +} + From 0e02a037b45722f505b995c7815ba6a2c977ea75 Mon Sep 17 00:00:00 2001 From: Eva Ho Date: Mon, 15 Dec 2025 17:49:24 -0500 Subject: [PATCH 3/4] clean up --- app/ui/app_test.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/app/ui/app_test.go b/app/ui/app_test.go index 425ed4f88..83d959348 100644 --- a/app/ui/app_test.go +++ b/app/ui/app_test.go @@ -16,7 +16,6 @@ func TestEmbeddedAssets(t *testing.T) { t.Fatal("app/dist not found in embedded filesystem - UI not built") } - // Check index.html exists data, err := fs.ReadFile(fsys, "index.html") if err != nil { t.Fatal("index.html not found - run 'go generate' first") @@ -24,17 +23,14 @@ func TestEmbeddedAssets(t *testing.T) { html := string(data) - // Check it's NOT the source version 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.") } - // Check it IS the built version if !strings.Contains(html, "/assets/index-") { t.Fatal("Wrong index.html embedded: missing /assets/index-* (production paths). The UI was not built correctly.") } - // Check assets directory exists if _, err := fsys.Open("assets"); err != nil { t.Fatal("assets/ directory not found - UI build incomplete") } From fc1f10cd0bcfc28b5ca0dfd8d6305217fa991546 Mon Sep 17 00:00:00 2001 From: Eva Ho Date: Tue, 16 Dec 2025 13:28:15 -0500 Subject: [PATCH 4/4] fix test --- app/ui/app.go | 10 +++++----- app/ui/app_test.go | 13 ++++++------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/app/ui/app.go b/app/ui/app.go index e359215ee..f84dd8d2e 100644 --- a/app/ui/app.go +++ b/app/ui/app.go @@ -33,19 +33,19 @@ func (s *Server) appHandler() http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { p := strings.TrimPrefix(r.URL.Path, "/") - + 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) return } - + // Fallback – serve index.html for unknown paths so React Router works data, err := fs.ReadFile(fsys, "index.html") if err != nil { @@ -56,7 +56,7 @@ func (s *Server) appHandler() http.Handler { } return } - + w.Header().Set("Content-Type", "text/html; charset=utf-8") http.ServeContent(w, r, "index.html", time.Time{}, bytes.NewReader(data)) }) diff --git a/app/ui/app_test.go b/app/ui/app_test.go index 83d959348..fedacb3ac 100644 --- a/app/ui/app_test.go +++ b/app/ui/app_test.go @@ -15,26 +15,25 @@ func TestEmbeddedAssets(t *testing.T) { 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") } -