diff --git a/beszel/internal/hub/hub.go b/beszel/internal/hub/hub.go index 3f56ca5..e4a3adf 100644 --- a/beszel/internal/hub/hub.go +++ b/beszel/internal/hub/hub.go @@ -112,6 +112,8 @@ func (h *Hub) initialize(e *core.ServeEvent) error { // set URL if BASE_URL env is set if h.appURL != "" { settings.Meta.AppURL = h.appURL + } else { + h.appURL = settings.Meta.AppURL } if err := e.App.Save(settings); err != nil { return err diff --git a/beszel/internal/hub/server_development.go b/beszel/internal/hub/server_development.go index e7a34d5..b44f6e8 100644 --- a/beszel/internal/hub/server_development.go +++ b/beszel/internal/hub/server_development.go @@ -3,18 +3,74 @@ package hub import ( + "beszel" + "fmt" + "io" + "log/slog" + "net/http" "net/http/httputil" "net/url" + "strings" "github.com/pocketbase/pocketbase/core" ) +// Wraps http.RoundTripper to modify dev proxy HTML responses +type responseModifier struct { + transport http.RoundTripper + hub *Hub +} + +func (rm *responseModifier) RoundTrip(req *http.Request) (*http.Response, error) { + resp, err := rm.transport.RoundTrip(req) + if err != nil { + return resp, err + } + // Only modify HTML responses + contentType := resp.Header.Get("Content-Type") + if !strings.Contains(contentType, "text/html") { + return resp, nil + } + body, err := io.ReadAll(resp.Body) + if err != nil { + return resp, err + } + resp.Body.Close() + // Create a new response with the modified body + modifiedBody := rm.modifyHTML(string(body)) + resp.Body = io.NopCloser(strings.NewReader(modifiedBody)) + resp.ContentLength = int64(len(modifiedBody)) + resp.Header.Set("Content-Length", fmt.Sprintf("%d", len(modifiedBody))) + + return resp, nil +} + +func (rm *responseModifier) modifyHTML(html string) string { + parsedURL, err := url.Parse(rm.hub.appURL) + if err != nil { + return html + } + // fix base paths in html if using subpath + basePath := strings.TrimSuffix(parsedURL.Path, "/") + "/" + html = strings.ReplaceAll(html, "./", basePath) + html = strings.Replace(html, "{{V}}", beszel.Version, 1) + html = strings.Replace(html, "{{HUB_URL}}", rm.hub.appURL, 1) + return html +} + // startServer sets up the development server for Beszel func (h *Hub) startServer(se *core.ServeEvent) error { + slog.Info("starting server", "appURL", h.appURL) proxy := httputil.NewSingleHostReverseProxy(&url.URL{ Scheme: "http", Host: "localhost:5173", }) + + proxy.Transport = &responseModifier{ + transport: http.DefaultTransport, + hub: h, + } + se.Router.GET("/{path...}", func(e *core.RequestEvent) error { proxy.ServeHTTP(e.Response, e.Request) return nil diff --git a/beszel/internal/hub/server_production.go b/beszel/internal/hub/server_production.go index 831d0b5..0161f3f 100644 --- a/beszel/internal/hub/server_production.go +++ b/beszel/internal/hub/server_production.go @@ -24,9 +24,9 @@ func (h *Hub) startServer(se *core.ServeEvent) error { // fix base paths in html if using subpath basePath := strings.TrimSuffix(parsedURL.Path, "/") + "/" indexFile, _ := fs.ReadFile(site.DistDirFS, "index.html") - indexContent := strings.ReplaceAll(string(indexFile), "./", basePath) - indexContent = strings.Replace(indexContent, "{{V}}", beszel.Version, 1) - indexContent = strings.Replace(indexContent, "{{HUB_URL}}", h.appURL, 1) + html := strings.ReplaceAll(string(indexFile), "./", basePath) + html = strings.Replace(html, "{{V}}", beszel.Version, 1) + html = strings.Replace(html, "{{HUB_URL}}", h.appURL, 1) // set up static asset serving staticPaths := [2]string{"/static/", "/assets/"} serveStatic := apis.Static(site.DistDirFS, false) @@ -45,7 +45,7 @@ func (h *Hub) startServer(se *core.ServeEvent) error { e.Response.Header().Del("X-Frame-Options") e.Response.Header().Set("Content-Security-Policy", csp) } - return e.HTML(http.StatusOK, indexContent) + return e.HTML(http.StatusOK, html) }) return nil } diff --git a/beszel/site/vite.config.ts b/beszel/site/vite.config.ts index 06c6da3..ce6a8ad 100644 --- a/beszel/site/vite.config.ts +++ b/beszel/site/vite.config.ts @@ -3,7 +3,6 @@ import path from "path" import tailwindcss from "@tailwindcss/vite" import react from "@vitejs/plugin-react-swc" import { lingui } from "@lingui/vite-plugin" -import { version } from "./package.json" export default defineConfig({ base: "./", @@ -13,13 +12,6 @@ export default defineConfig({ }), lingui(), tailwindcss(), - { - name: "replace version in index.html during dev", - apply: "serve", - transformIndexHtml(html) { - return html.replace("{{V}}", version).replace("{{HUB_URL}}", "") - }, - }, ], esbuild: { legalComments: "external",