From 0df5507c81afcef767908e7381d3354b22fb3f89 Mon Sep 17 00:00:00 2001 From: Will Norris Date: Fri, 18 Aug 2023 16:46:48 -0700 Subject: [PATCH] client/web: combine embeds into a single embed.FS instead of embedding each file individually, embed them all into a single embed filesystem. This is basically a noop for the current frontend, but sets things up a little cleaner for the new frontend. Also added an embed.FS for the source files needed to build the new frontend. These files are not actually embedded into the binary (since it is a blank identifier), but causes `go mod vendor` to copy them into the vendor directory. Updates tailscale/corp#13775 Signed-off-by: Will Norris --- client/web/web.go | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/client/web/web.go b/client/web/web.go index 37df7a644..bf7165b3e 100644 --- a/client/web/web.go +++ b/client/web/web.go @@ -9,7 +9,7 @@ "context" "crypto/rand" "crypto/tls" - _ "embed" + "embed" "encoding/json" "encoding/xml" "fmt" @@ -36,16 +36,19 @@ "tailscale.com/version/distro" ) -//go:embed web.html -var webHTML string +// This contains all files needed to build the frontend assets. +// Because we assign this to the blank identifier, it does not actually embed the files. +// However, this does cause `go mod vendor` to include the files when vendoring the package. +// External packages that use the web client can `go mod vendor`, run `yarn build` to +// build the assets, then those asset bundles will be able to be embedded. +// +//go:embed yarn.lock index.html *.js *.json src/**/* +var _ embed.FS -//go:embed web.css -var webCSS string +//go:embed web.html web.css auth-redirect.html +var embeddedFS embed.FS -//go:embed auth-redirect.html -var authenticationRedirectHTML string - -var tmpl *template.Template +var tmpls *template.Template // Server is the backend server for a Tailscale web client. type Server struct { @@ -84,8 +87,7 @@ func NewServer(devMode bool, lc *tailscale.LocalClient) (s *Server, cleanup func } func init() { - tmpl = template.Must(template.New("web.html").Parse(webHTML)) - template.Must(tmpl.New("web.css").Parse(webCSS)) + tmpls = template.Must(template.New("").ParseFS(embeddedFS, "*")) } // authorize returns the name of the user accessing the web UI after verifying @@ -301,7 +303,9 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { switch { case r.URL.Path == "/redirect" || r.URL.Path == "/redirect/": - io.WriteString(w, authenticationRedirectHTML) + if err := tmpls.ExecuteTemplate(w, "auth-redirect.html", nil); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + } return case r.Method == "POST": s.servePostNodeUpdate(w, r) @@ -380,7 +384,7 @@ func (s *Server) serveGetNodeData(w http.ResponseWriter, r *http.Request, user s return } buf := new(bytes.Buffer) - if err := tmpl.Execute(buf, *data); err != nil { + if err := tmpls.ExecuteTemplate(buf, "web.html", data); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return }