@@ -346,7 +346,7 @@ func (s *Server) AddPrometheusHandler() {
346346}
347347
348348// AddFrontend enables serving the embedded Svelte frontend.
349- func (s * Server ) AddFrontend () {
349+ func (s * Server ) AddFrontend (devMode bool ) {
350350 s .router .Group (func (r chi.Router ) {
351351 s .traceInstaller .Install (r , "frontend" ,
352352 // The frontend serves a lot of static files on different paths. To save on cardinality, we override the
@@ -357,7 +357,14 @@ func (s *Server) AddFrontend() {
357357 )
358358
359359 r .Handle ("/favicon.ico" , FaviconHandler ())
360- r .Handle ("/*" , SvelteKitHandler ())
360+
361+ if devMode {
362+ // In dev mode, proxy to Vite dev server
363+ r .Handle ("/*" , ViteProxyHandler ())
364+ } else {
365+ // Production: serve embedded files
366+ r .Handle ("/*" , SvelteKitHandler ())
367+ }
361368 })
362369}
363370
@@ -1533,6 +1540,23 @@ func SvelteKitHandler() http.Handler {
15331540 })
15341541}
15351542
1543+ // ViteProxyHandler returns an http.Handler that proxies requests to the Vite dev server.
1544+ func ViteProxyHandler () http.Handler {
1545+ target , _ := url .Parse ("http://localhost:5173" )
1546+ proxy := httputil .NewSingleHostReverseProxy (target )
1547+ proxy .Director = func (req * http.Request ) {
1548+ req .URL .Scheme = target .Scheme
1549+ req .URL .Host = target .Host
1550+ req .Host = target .Host
1551+ slog .Debug ("Proxying request to Vite" , "path" , req .URL .Path )
1552+ }
1553+ proxy .ErrorHandler = func (w http.ResponseWriter , r * http.Request , err error ) {
1554+ slog .Error ("Vite proxy error" , "err" , err , "path" , r .URL .Path )
1555+ http .Error (w , "Vite dev server unavailable. Make sure it's running on http://localhost:5173" , http .StatusBadGateway )
1556+ }
1557+ return proxy
1558+ }
1559+
15361560func PrometheusMiddleware (next http.Handler ) http.Handler {
15371561 return http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
15381562 start := time .Now ()
0 commit comments