diff --git a/cmd/tsconnect/common.go b/cmd/tsconnect/common.go index 20ee449f0..9c112f8ac 100644 --- a/cmd/tsconnect/common.go +++ b/cmd/tsconnect/common.go @@ -216,10 +216,41 @@ func buildWasm(dev bool) ([]byte, error) { if err != nil { return nil, fmt.Errorf("Cannot build main.wasm: %w", err) } - log.Printf("Built wasm in %v\n", time.Since(start)) + log.Printf("Built wasm in %v\n", time.Since(start).Round(time.Millisecond)) + + if !dev { + err := runWasmOpt(outputPath) + if err != nil { + return nil, fmt.Errorf("Cannot run wasm-opt: %w", err) + } + } + return os.ReadFile(outputPath) } +func runWasmOpt(path string) error { + start := time.Now() + stat, err := os.Stat(path) + if err != nil { + return fmt.Errorf("Cannot stat %v: %w", path, err) + } + startSize := stat.Size() + cmd := exec.Command("../../tool/wasm-opt", "-Oz", path, "-o", path) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + err = cmd.Run() + if err != nil { + return fmt.Errorf("Cannot run wasm-opt: %w", err) + } + stat, err = os.Stat(path) + if err != nil { + return fmt.Errorf("Cannot stat %v: %w", path, err) + } + endSize := stat.Size() + log.Printf("Ran wasm-opt in %v, size dropped by %dK\n", time.Since(start).Round(time.Millisecond), (startSize-endSize)/1024) + return nil +} + // installJSDeps installs the JavaScript dependencies specified by package.json func installJSDeps() error { log.Printf("Installing JS deps...\n") @@ -256,7 +287,7 @@ func setupEsbuildTailwind(build esbuild.PluginBuild, dev bool) { } cmd := exec.Command(*yarnPath, yarnArgs...) tailwindOutput, err := cmd.Output() - log.Printf("Ran tailwind in %v\n", time.Since(start)) + log.Printf("Ran tailwind in %v\n", time.Since(start).Round(time.Millisecond)) if err != nil { if exitErr, ok := err.(*exec.ExitError); ok { log.Printf("Tailwind stderr: %s", exitErr.Stderr) diff --git a/tool/binaryen.rev b/tool/binaryen.rev new file mode 100644 index 000000000..bc6298e80 --- /dev/null +++ b/tool/binaryen.rev @@ -0,0 +1 @@ +110 diff --git a/tool/wasm-opt b/tool/wasm-opt new file mode 100755 index 000000000..08f3e5bfb --- /dev/null +++ b/tool/wasm-opt @@ -0,0 +1,74 @@ +#!/bin/sh +# +# This script acts like the "wasm-opt" command from the Binaryen toolchain, but +# uses Tailscale's currently-desired version, downloading it first if necessary. + +set -eu + +BINARYEN_DIR="$HOME/.cache/tailscale-binaryen" +read -r BINARYEN_REV < "$(dirname "$0")/binaryen.rev" +# This works for Linux and Darwin, which is sufficient +# (we do not build for other targets). +OS=$(uname -s | tr A-Z a-z) +if [ "$OS" = "darwin" ]; then + # Binaryen uses the name "macos". + OS="macos" +fi +ARCH="$(uname -m)" +if [ "$ARCH" = "aarch64" ]; then + # Binaryen uses the name "arm64". + ARCH="arm64" +fi + +install_binaryen() { + BINARYEN_URL="https://github.com/WebAssembly/binaryen/releases/download/version_${BINARYEN_REV}/binaryen-version_${BINARYEN_REV}-${ARCH}-${OS}.tar.gz" + install_tool "wasm-opt" $BINARYEN_REV $BINARYEN_DIR $BINARYEN_URL +} + +install_tool() { + TOOL=$1 + REV=$2 + TOOLCHAIN=$3 + URL=$4 + + archive="$TOOLCHAIN-$REV.tar.gz" + mark="$TOOLCHAIN.extracted" + extracted= + [ ! -e "$mark" ] || read -r extracted junk <$mark + + if [ "$extracted" = "$REV" ] && [ -e "$TOOLCHAIN/bin/$TOOL" ]; then + # Already extracted, continue silently + return 0 + fi + echo "" + + rm -f "$archive.new" "$TOOLCHAIN.extracted" + if [ ! -e "$archive" ]; then + log "Need to download $TOOL '$REV' from $URL." + curl -f -L -o "$archive.new" $URL + rm -f "$archive" + mv "$archive.new" "$archive" + fi + + log "Extracting $TOOL '$REV' into '$TOOLCHAIN'." >&2 + rm -rf "$TOOLCHAIN" + mkdir -p "$TOOLCHAIN" + (cd "$TOOLCHAIN" && tar --strip-components=1 -xf "$archive") + echo "$REV" >$mark +} + +log() { + echo "$@" >&2 +} + +if [ "${BINARYEN_DIR}" = "SKIP" ] || + [ "${OS}" != "macos" -a "${OS}" != "linux" ] || + [ "${ARCH}" != "x86_64" -a "${ARCH}" != "arm64" ]; then + log "Unsupported OS (${OS}) and architecture (${ARCH}) combination." + log "Using existing wasm-opt (`which wasm-opt`)." + exec wasm-opt "$@" +fi + +install_binaryen + +"$BINARYEN_DIR/bin/wasm-opt" "$@"