5 Commits

Author SHA1 Message Date
a0d81ca2be Switch repo 2022-06-01 14:58:23 +02:00
30ab451d3a Add simple serve 2022-05-11 12:35:55 +02:00
8e7d4d2978 Improve the replace feature to support env variables 2022-04-18 23:55:46 +02:00
ea1d5ea911 Merge remote-tracking branch 'origin/master' 2022-02-01 17:16:01 +01:00
12de91324e Add -c param and exclusion 2022-02-01 17:15:14 +01:00
3 changed files with 163 additions and 20 deletions

2
go.mod
View File

@ -1,4 +1,4 @@
module gitlab.codeblob.work/pk/gowebbuild
module github.com/trading-peter/gowebbuild
go 1.17

171
main.go
View File

@ -4,9 +4,12 @@ import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"net/http"
"os"
"os/signal"
"path/filepath"
"strings"
"syscall"
"time"
@ -22,35 +25,92 @@ var triggerReload = make(chan struct{})
type options struct {
ESBuild api.BuildOptions
Watch struct {
Path string
Exclude []string
}
Serve struct {
Path string
Port int
}
Copy []struct {
Src string
Dest string
}
Replace []struct {
Pattern string
Search string
Replace string
}
}
func main() {
opts := options{}
cfgContent, err := os.ReadFile("./.gowebbuild.json")
if err != nil {
fmt.Printf("%+v\n", err)
os.Exit(1)
}
err = json.Unmarshal(cfgContent, &opts)
if err != nil {
fmt.Printf("%+v\n", err)
os.Exit(1)
}
flow := &goyek.Flow{}
opts := options{}
flow.Register(goyek.Task{
Name: "watch-frontend",
Usage: "",
cfgPathParam := flow.RegisterStringParam(goyek.StringParam{
Name: "c",
Usage: "Path to config file config file.",
Default: "./.gowebbuild.json",
})
prodParam := flow.RegisterBoolParam(goyek.BoolParam{
Name: "p",
Usage: "Use production ready build settings",
Default: false,
})
buildOnly := goyek.Task{
Name: "build",
Usage: "",
Params: goyek.Params{cfgPathParam, prodParam},
Action: func(tf *goyek.TF) {
cfgPath := cfgPathParam.Get(tf)
cfgContent, err := os.ReadFile(cfgPath)
if err != nil {
fmt.Printf("%+v\n", err)
os.Exit(1)
}
err = json.Unmarshal(cfgContent, &opts)
if err != nil {
fmt.Printf("%+v\n", err)
os.Exit(1)
}
cp(opts)
if prodParam.Get(tf) {
opts.ESBuild.MinifyIdentifiers = true
opts.ESBuild.MinifySyntax = true
opts.ESBuild.MinifyWhitespace = true
opts.ESBuild.Sourcemap = api.SourceMapNone
}
api.Build(opts.ESBuild)
replace(opts)
},
}
watch := goyek.Task{
Name: "watch",
Usage: "",
Params: goyek.Params{cfgPathParam},
Action: func(tf *goyek.TF) {
cfgPath := cfgPathParam.Get(tf)
cfgContent, err := os.ReadFile(cfgPath)
if err != nil {
fmt.Printf("%+v\n", err)
os.Exit(1)
}
err = json.Unmarshal(cfgContent, &opts)
if err != nil {
fmt.Printf("%+v\n", err)
os.Exit(1)
}
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
@ -60,6 +120,11 @@ func main() {
w := watcher.New()
w.SetMaxEvents(1)
w.FilterOps(watcher.Write, watcher.Rename, watcher.Move, watcher.Create, watcher.Remove)
if len(opts.Watch.Exclude) > 0 {
w.Ignore(opts.Watch.Exclude...)
}
if err := w.AddRecursive(opts.Watch.Path); err != nil {
fmt.Println(err.Error())
os.Exit(1)
@ -72,6 +137,7 @@ func main() {
fmt.Printf("File %s changed\n", event.Name())
cp(opts)
build(opts)
replace(opts)
case err := <-w.Error:
fmt.Println(err.Error())
case <-w.Closed:
@ -82,6 +148,10 @@ func main() {
fmt.Printf("Watching %d elements in %s\n", len(w.WatchedFiles()), opts.Watch.Path)
cp(opts)
build(opts)
replace(opts)
if err := w.Start(time.Millisecond * 100); err != nil {
fmt.Println(err.Error())
}
@ -104,12 +174,33 @@ func main() {
}
}()
if opts.Serve.Path != "" {
go func() {
port := 8888
if opts.Serve.Port != 0 {
port = opts.Serve.Port
}
http.Handle("/", http.FileServer(http.Dir(opts.Serve.Path)))
fmt.Printf("Serving contents of %s at :%d\n", opts.Serve.Path, port)
err := http.ListenAndServe(fmt.Sprintf(":%d", port), nil)
if err != nil {
fmt.Printf("%+v\n", err.Error())
os.Exit(1)
}
}()
}
<-c
fmt.Println("\nExit")
os.Exit(0)
},
})
}
flow.DefaultTask = flow.Register(watch)
flow.Register(buildOnly)
flow.Main()
}
@ -143,6 +234,50 @@ func cp(opts options) {
}
}
func replace(opts options) {
if len(opts.Replace) == 0 {
fmt.Println("Nothing to replace")
return
}
for _, op := range opts.Replace {
paths, err := filepath.Glob(op.Pattern)
if err != nil {
fmt.Printf("Invalid glob pattern: %s\n", op.Pattern)
continue
}
for _, p := range paths {
if !isFile(p) {
continue
}
read, err := ioutil.ReadFile(p)
if err != nil {
fmt.Printf("%+v\n", err)
os.Exit(1)
}
r := op.Replace
if strings.HasPrefix(op.Replace, "$") {
r = os.ExpandEnv(op.Replace)
}
count := strings.Count(string(read), op.Search)
if count > 0 {
fmt.Printf("Replacing %d occurrences of '%s' with '%s' in %s\n", count, op.Search, r, p)
newContents := strings.ReplaceAll(string(read), op.Search, r)
err = ioutil.WriteFile(p, []byte(newContents), 0)
if err != nil {
fmt.Printf("%+v\n", err)
os.Exit(1)
}
}
}
}
}
func isFile(path string) bool {
stat, err := os.Stat(path)

View File

@ -1,6 +1,7 @@
{
"Watch": {
"Path": "./frontend/src"
"Path": "./frontend/src",
"Exclude": [ "./dist" ]
},
"Copy": [
{
@ -24,6 +25,13 @@
"Dest": "./api/frontend-dist"
}
],
"Replace": [
{
"Pattern": "*.go|*.js|*.html",
"Search": "Something",
"Replace": "This"
}
],
"ESBuild": {
"EntryPoints": [
"./frontend/src/the-app.js",