mirror of https://github.com/tailscale/tailscale/
client/web: add barebones vite dev setup
Currently just serving a "Hello world" page when running the web cli in --dev mode. Updates tailscale/corp#13775 Co-authored-by: Will Norris <will@tailscale.com> Signed-off-by: Sonia Appasamy <sonia@tailscale.com>pull/8847/head
parent
215480a022
commit
16bc9350e3
@ -0,0 +1,75 @@
|
|||||||
|
// Copyright (c) Tailscale Inc & AUTHORS
|
||||||
|
// SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
|
||||||
|
package web
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httputil"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// startDevServer starts the JS dev server that does on-demand rebuilding
|
||||||
|
// and serving of web client JS and CSS resources.
|
||||||
|
func (s *Server) startDevServer() (cleanup func()) {
|
||||||
|
root := gitRootDir()
|
||||||
|
webClientPath := filepath.Join(root, "client", "web")
|
||||||
|
|
||||||
|
yarn := filepath.Join(root, "tool", "yarn")
|
||||||
|
node := filepath.Join(root, "tool", "node")
|
||||||
|
vite := filepath.Join(webClientPath, "node_modules", ".bin", "vite")
|
||||||
|
|
||||||
|
log.Printf("installing JavaScript deps using %s... (might take ~30s)", yarn)
|
||||||
|
out, err := exec.Command(yarn, "--non-interactive", "-s", "--cwd", webClientPath, "install").CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("error running tailscale web's yarn install: %v, %s", err, out)
|
||||||
|
}
|
||||||
|
log.Printf("starting JavaScript dev server...")
|
||||||
|
cmd := exec.Command(node, vite)
|
||||||
|
cmd.Dir = webClientPath
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
if err := cmd.Start(); err != nil {
|
||||||
|
log.Fatalf("Starting JS dev server: %v", err)
|
||||||
|
}
|
||||||
|
log.Printf("JavaScript dev server running as pid %d", cmd.Process.Pid)
|
||||||
|
return func() {
|
||||||
|
cmd.Process.Signal(os.Interrupt)
|
||||||
|
err := cmd.Wait()
|
||||||
|
log.Printf("JavaScript dev server exited: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) addProxyToDevServer() {
|
||||||
|
if !s.devMode {
|
||||||
|
return // only using Vite proxy in dev mode
|
||||||
|
}
|
||||||
|
// We use Vite to develop on the web client.
|
||||||
|
// Vite starts up its own local server for development,
|
||||||
|
// which we proxy requests to from Server.ServeHTTP.
|
||||||
|
// Here we set up the proxy to Vite's server.
|
||||||
|
handleErr := func(w http.ResponseWriter, r *http.Request, err error) {
|
||||||
|
w.Header().Set("Content-Type", "text/plain")
|
||||||
|
w.WriteHeader(http.StatusBadGateway)
|
||||||
|
w.Write([]byte("The web client development server isn't running. " +
|
||||||
|
"Run `./tool/yarn --cwd client/web start` from " +
|
||||||
|
"the repo root to start the development server."))
|
||||||
|
w.Write([]byte("\n\nError: " + err.Error()))
|
||||||
|
}
|
||||||
|
viteTarget, _ := url.Parse("http://127.0.0.1:4000")
|
||||||
|
s.devProxy = httputil.NewSingleHostReverseProxy(viteTarget)
|
||||||
|
s.devProxy.ErrorHandler = handleErr
|
||||||
|
}
|
||||||
|
|
||||||
|
func gitRootDir() string {
|
||||||
|
top, err := exec.Command("git", "rev-parse", "--show-toplevel").Output()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("failed to find git top level (not in corp git?): %v", err)
|
||||||
|
}
|
||||||
|
return strings.TrimSpace(string(top))
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
<!doctype html>
|
||||||
|
Hello world
|
||||||
|
</html>
|
@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"name": "webui",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"engines": {
|
||||||
|
"node": "18.16.1",
|
||||||
|
"yarn": "1.22.19"
|
||||||
|
},
|
||||||
|
"private": true,
|
||||||
|
"dependencies": {},
|
||||||
|
"devDependencies": {
|
||||||
|
"tailwindcss": "^3.1.6",
|
||||||
|
"typescript": "^4.7.4",
|
||||||
|
"vite": "^4.3.9",
|
||||||
|
"@vitejs/plugin-react-swc": "^3.3.2",
|
||||||
|
"vite-tsconfig-paths": "^3.5.0",
|
||||||
|
"vite-plugin-svgr": "^3.2.0",
|
||||||
|
"vite-plugin-rewrite-all": "^1.0.1",
|
||||||
|
"vitest": "^0.32.0"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"build": "vite build",
|
||||||
|
"start": "vite",
|
||||||
|
"lint": "tsc --noEmit",
|
||||||
|
"test": "vitest"
|
||||||
|
},
|
||||||
|
"prettier": {
|
||||||
|
"semi": false,
|
||||||
|
"printWidth": 80
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,69 @@
|
|||||||
|
/// <reference types="vitest" />
|
||||||
|
import { createLogger, defineConfig } from "vite"
|
||||||
|
import rewrite from "vite-plugin-rewrite-all"
|
||||||
|
import svgr from "vite-plugin-svgr"
|
||||||
|
import paths from "vite-tsconfig-paths"
|
||||||
|
|
||||||
|
// Use a custom logger that filters out Vite's logging of server URLs, since
|
||||||
|
// they are an attractive nuisance (we run a proxy in front of Vite, and the
|
||||||
|
// tailscale web client should be accessed through that).
|
||||||
|
// Unfortunately there's no option to disable this logging, so the best we can
|
||||||
|
// do it to ignore calls from a specific function.
|
||||||
|
const filteringLogger = createLogger(undefined, { allowClearScreen: false })
|
||||||
|
const originalInfoLog = filteringLogger.info
|
||||||
|
filteringLogger.info = (...args) => {
|
||||||
|
if (new Error("ignored").stack?.includes("printServerUrls")) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
originalInfoLog.apply(filteringLogger, args)
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://vitejs.dev/config/
|
||||||
|
export default defineConfig({
|
||||||
|
base: "/",
|
||||||
|
plugins: [
|
||||||
|
paths(),
|
||||||
|
svgr(),
|
||||||
|
// By default, the Vite dev server doesn't handle dots
|
||||||
|
// in path names and treats them as static files.
|
||||||
|
// This plugin changes Vite's routing logic to fix this.
|
||||||
|
// See: https://github.com/vitejs/vite/issues/2415
|
||||||
|
rewrite(),
|
||||||
|
],
|
||||||
|
build: {
|
||||||
|
outDir: "build",
|
||||||
|
sourcemap: true,
|
||||||
|
},
|
||||||
|
esbuild: {
|
||||||
|
logOverride: {
|
||||||
|
// Silence a warning about `this` being undefined in ESM when at the
|
||||||
|
// top-level. The way JSX is transpiled causes this to happen, but it
|
||||||
|
// isn't a problem.
|
||||||
|
// See: https://github.com/vitejs/vite/issues/8644
|
||||||
|
"this-is-undefined-in-esm": "silent",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
server: {
|
||||||
|
// This needs to be 127.0.0.1 instead of localhost, because of how our
|
||||||
|
// Go proxy connects to it.
|
||||||
|
host: "127.0.0.1",
|
||||||
|
// If you change the port, be sure to update the proxy in adminhttp.go too.
|
||||||
|
port: 4000,
|
||||||
|
// Don't proxy the WebSocket connection used for live reloading by running
|
||||||
|
// it on a separate port.
|
||||||
|
hmr: {
|
||||||
|
protocol: "ws",
|
||||||
|
port: 4001,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
test: {
|
||||||
|
exclude: ["**/node_modules/**", "**/dist/**"],
|
||||||
|
testTimeout: 20000,
|
||||||
|
environment: "jsdom",
|
||||||
|
deps: {
|
||||||
|
inline: ["date-fns", /\.wasm\?url$/],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
clearScreen: false,
|
||||||
|
customLogger: filteringLogger,
|
||||||
|
})
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue