2022-06-07 21:24:22 +00:00
|
|
|
// Copyright (c) 2022 Tailscale Inc & AUTHORS All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2022-07-20 01:04:09 +00:00
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
2022-06-07 21:24:22 +00:00
|
|
|
"io/ioutil"
|
|
|
|
"log"
|
|
|
|
"os"
|
2022-07-20 01:04:09 +00:00
|
|
|
"path"
|
2022-06-07 21:24:22 +00:00
|
|
|
"path/filepath"
|
|
|
|
|
2022-08-03 01:16:24 +00:00
|
|
|
"tailscale.com/util/precompress"
|
2022-06-07 21:24:22 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func runBuild() {
|
|
|
|
buildOptions, err := commonSetup(prodMode)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("Cannot setup: %v", err)
|
|
|
|
}
|
|
|
|
|
2022-07-27 22:46:13 +00:00
|
|
|
log.Printf("Linting...\n")
|
|
|
|
if err := runYarn("lint"); err != nil {
|
|
|
|
log.Fatalf("Linting failed: %v", err)
|
|
|
|
}
|
|
|
|
|
2022-08-24 01:05:23 +00:00
|
|
|
if err := cleanDir(*distDir, "placeholder"); err != nil {
|
2022-07-20 01:04:09 +00:00
|
|
|
log.Fatalf("Cannot clean %s: %v", *distDir, err)
|
2022-06-07 21:24:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
buildOptions.Write = true
|
|
|
|
buildOptions.MinifyWhitespace = true
|
|
|
|
buildOptions.MinifyIdentifiers = true
|
|
|
|
buildOptions.MinifySyntax = true
|
|
|
|
|
|
|
|
buildOptions.EntryNames = "[dir]/[name]-[hash]"
|
|
|
|
buildOptions.AssetNames = "[name]-[hash]"
|
|
|
|
buildOptions.Metafile = true
|
|
|
|
|
2022-08-24 01:05:23 +00:00
|
|
|
result := runEsbuild(*buildOptions)
|
2022-06-07 21:24:22 +00:00
|
|
|
|
|
|
|
// Preserve build metadata so we can extract hashed file names for serving.
|
2022-07-20 01:04:09 +00:00
|
|
|
metadataBytes, err := fixEsbuildMetadataPaths(result.Metafile)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("Cannot fix esbuild metadata paths: %v", err)
|
|
|
|
}
|
|
|
|
if err := ioutil.WriteFile(path.Join(*distDir, "/esbuild-metadata.json"), metadataBytes, 0666); err != nil {
|
2022-06-07 21:24:22 +00:00
|
|
|
log.Fatalf("Cannot write metadata: %v", err)
|
|
|
|
}
|
|
|
|
|
2022-08-02 22:00:26 +00:00
|
|
|
if er := precompressDist(*fastCompression); err != nil {
|
2022-06-07 21:24:22 +00:00
|
|
|
log.Fatalf("Cannot precompress resources: %v", er)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-20 01:04:09 +00:00
|
|
|
// fixEsbuildMetadataPaths re-keys the esbuild metadata file to use paths
|
|
|
|
// relative to the dist directory (it normally uses paths relative to the cwd,
|
|
|
|
// which are akward if we're running with a different cwd at serving time).
|
|
|
|
func fixEsbuildMetadataPaths(metadataStr string) ([]byte, error) {
|
|
|
|
var metadata EsbuildMetadata
|
|
|
|
if err := json.Unmarshal([]byte(metadataStr), &metadata); err != nil {
|
|
|
|
return nil, fmt.Errorf("Cannot parse metadata: %w", err)
|
|
|
|
}
|
|
|
|
distAbsPath, err := filepath.Abs(*distDir)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("Cannot get absolute path from %s: %w", *distDir, err)
|
|
|
|
}
|
|
|
|
for outputPath, output := range metadata.Outputs {
|
|
|
|
outputAbsPath, err := filepath.Abs(outputPath)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("Cannot get absolute path from %s: %w", outputPath, err)
|
|
|
|
}
|
|
|
|
outputRelPath, err := filepath.Rel(distAbsPath, outputAbsPath)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("Cannot get relative path from %s: %w", outputRelPath, err)
|
|
|
|
}
|
|
|
|
delete(metadata.Outputs, outputPath)
|
|
|
|
metadata.Outputs[outputRelPath] = output
|
|
|
|
}
|
|
|
|
return json.Marshal(metadata)
|
|
|
|
}
|
|
|
|
|
2022-06-07 21:24:22 +00:00
|
|
|
func cleanDist() error {
|
2022-07-20 01:04:09 +00:00
|
|
|
log.Printf("Cleaning %s...\n", *distDir)
|
|
|
|
files, err := os.ReadDir(*distDir)
|
2022-06-07 21:24:22 +00:00
|
|
|
if err != nil {
|
2022-07-20 01:04:09 +00:00
|
|
|
if os.IsNotExist(err) {
|
|
|
|
return os.MkdirAll(*distDir, 0755)
|
|
|
|
}
|
2022-06-07 21:24:22 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, file := range files {
|
|
|
|
if file.Name() != "placeholder" {
|
2022-07-20 01:04:09 +00:00
|
|
|
if err := os.Remove(filepath.Join(*distDir, file.Name())); err != nil {
|
2022-06-07 21:24:22 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-08-02 22:00:26 +00:00
|
|
|
func precompressDist(fastCompression bool) error {
|
2022-07-20 01:04:09 +00:00
|
|
|
log.Printf("Pre-compressing files in %s/...\n", *distDir)
|
2022-08-03 01:16:24 +00:00
|
|
|
return precompress.PrecompressDir(*distDir, precompress.Options{
|
|
|
|
FastCompression: fastCompression,
|
|
|
|
ProgressFn: func(path string) {
|
|
|
|
log.Printf("Pre-compressing %v\n", path)
|
|
|
|
},
|
2022-06-07 21:24:22 +00:00
|
|
|
})
|
|
|
|
}
|