Wgo
Live reload for Go apps. Watch arbitrary files and respond with arbitrary commands. Supports running multiple commands in parallel.
Install / Use
/learn @bokwoon95/WgoREADME
Installation
You can download binaries from the release page, or use the Go command:
go install github.com/bokwoon95/wgo@latest
If you are on macOS, you may install it with Homebrew.
brew install wgo
Usage:
wgo [FLAGS] <command> [ARGUMENTS...]
wgo gcc -o main main.c
wgo go build -o main main.go
wgo -file .c gcc -o main main.c
wgo -file=.go go build -o main main.go
wgo run [FLAGS] [GO_BUILD_FLAGS] <package> [ARGUMENTS...]
wgo run main.go
wgo run -file .html main.go arg1 arg2 arg3
wgo run -file .html . arg1 arg2 arg3
wgo run -file=.css -file=.js -tags=fts5 ./cmd/my_project arg1 arg2 arg3
Pass in the -h flag to the wgo/wgo run to learn what flags there are i.e. wgo -h, wgo run -h
Core documentation resides at https://github.com/bokwoon95/wgo#quickstart
Why this exists
Too many file watchers either force you to wrap your commands into strings, require config files or log tons of noisy output to your stdout. In contrast, wgo is dead simple and silent by default. The implementation is also really short, most of it resides in just two files (wgo_cmd.go and main.go). You can read the entire codebase in one sitting, start here.
It can be used like go run.
Quickstart
You already know how to use wgo. Simply slap wgo in front of any command in order to have it rerun whenever a file changes.
# Run gcc.
$ gcc -Wall -o main main.c
# Run gcc whenever a file changes.
$ wgo gcc -Wall -o main main.c
wgo run
wgo run behaves exactly like go run except it runs again the moment any Go file changes. This can be used to live-reload Go servers. wgo run accepts the same flags as go run.
By default wgo run only watches .go files. To include additional file types such as .html, use the -file flag.
# Run main.go.
$ go run main.go
# Run main.go whenever a .go file changes.
$ wgo run main.go
# Any flag that can be passed to `go run` can also be passed to `wgo run`.
$ wgo run -tags=fts5 -race -trimpath main.go
Flags
wgo/wgo run take in additional flags. These flags must be passed in directly after wgo/wgo run, before invoking your command.
- -file/-xfile - Include/exclude files.
- -dir/-xdir - Include/exclude directories.
- -cd - Change to a different directory to run the commands.
- -root - Specify additional root directories to watch.
- -exit - Exit when the last command exits.
- -stdin - Enable stdin for the last command.
- -verbose - Log file events.
- -debounce - How quickly to react to file events. Lower debounce values will react quicker.
- -postpone - Postpone the first execution of the command until a file is modified.
- -poll - How often to poll for file changes. Zero or no value means no polling.
Advanced Usage
- Chaining commands
- Clear terminal on restart
- Running parallel wgo commands
- Don't stop the application on compile errors
- Debug Go code using GoLand or VSCode with wgo
Including and excluding files
To include specific files eligible for triggering a reload, use the -file flag. It takes in a regex, and files whose paths (relative to the root directory) match the regex are included. You can provide multiple -file flags.
Path separators are always forward slash, even on Windows.
If no -file flag is provided, every file is included by default unless it is explicitly excluded by the -xfile flag.
# Run sass whenever an .scss file changes.
$ wgo -file .scss sass assets/styles.scss assets/styles.css
# Run main.go whenever a .go or .html or .css file changes.
$ wgo run -file .html -file .css main.go
# Run main.go when foo/bar/baz.go changes.
$ wgo run -file '^foo/bar/baz.go$' main.go
To exclude specific files, use the -xfile flag. It takes in a regex (like -file) but if it matches with a file path that file is excluded.
The -xfile flag takes higher precedence than the -file flag so you can include a large group of files using a -file flag and surgically ignore specific files from that group using an -xfile flag.
# `go test` writes to coverage.out, which counts as a changed file which triggers
# `go test` to run again which generates coverage.out again in an infinite loop.
# Avoid this by excluding any file matching 'coverage.out'.
$ wgo -xfile coverage.out go test . -race -coverprofile=coverage.out
# Probably better to specify `-file .go` in order to rerun `go test` only when
# .go files change.
$ wgo -file .go go test . -race -coverprofile=coverage.out
Regex dot literals
The -file flag takes in regexes like .html or .css.
$ wgo run -file .html -file .css main.go
Technically the dot . matches any character, but file extensions are such a common pattern that wgo includes a slight modification to the regex matching rules:
Any dot . immediately followed by a letter [a-zA-Z] is treated as a dot literal i.e. \.
So .css really means \.css, but .* still means .* because * is not a letter. If you really want to use the dot . wildcard followed by a letter, wrap it in (a bracket group) so that it is not immediately followed by a letter i.e. (.)abc.
Including and excluding directories
To only watch specific directories, use the -dir flag. It takes in a regex, and directories whose paths (relative to the root directory) match the regex are included. You can provide multiple -dir flags.
Path separators are always forward slash, even on Windows.
# Run sass whenever an .scss file in the assets directory changes.
$ wgo -dir assets -file .scss sass assets/styles.scss assets/styles.css
# Run main.go whenever something in the foo directory or bar/baz directory changes.
$ wgo run -dir foo -dir bar/baz main.go
# Run main.go whenever something in the foo/bar/baz directory changes.
$ wgo run -dir '^foo/bar/baz$' main.go
To exclude specific directories, use the -xdir flag. It takes in a regex (like -dir) but if it matches with a directory path that directory is excluded from being watched.
# Run main.go whenever a file changes, ignoring any directory called node_modules.
$ wgo run -xdir node_modules main.go
In practice you don't have to exclude node_modules because it's already excluded by default (together with .git, .hg, .svn, .idea, .vscode and .settings). If you do want to watch any of those directories, you should explicitly include it with the -dir flag.
Chaining commands
Commands can be chained using the :: separator. Subsequent commands are executed only when the previous command succeeds.
# Run `make build` followed by `make run` whenever a file changes.
$ wgo make build :: make run
# Run `go build` followed by the built binary whenever a .go file changes.
$ wgo -file .go go build -o main main.go :: ./main
# Clear the screen with `clear` before running `go test`.
# Windows users should use `cls` instead of `clear`.
$ wgo -file .go clear :: go test . -race -coverprofile=coverage.out
Escaping the command separator
Since :: designates the command separator, if you actually need to pass in a :: string an an argument to a command you should escape it by appending an extra : to it. So :: is escaped to :::, ::: is escaped to ::::, and so on.
Shell wrapping
Chained commands execute in their own independent environment and are not implicitly wrapped in a shell. This can be a problem if you want to use shell specific commands like if-else statements or if you want to pass data between commands. In this case you should explicitly wrap the command(s) in a shell using the form sh -c '<command>' (or pwsh.exe -command '<command>' if you're on Windows).
# bash: echo "passed" or "failed" depending on whether the program succeeds.
$ wgo -file .go go build -o main main.go :: bash -c 'if ./main; then echo "passed"; else echo "failed"; fi'
# powershell: echo "passed" or "failed" depending on whether the program succeeds.
$ wgo -file .go go build -o main main.go :: pwsh.exe -command './main; if ($LastExitCode -eq 0) { echo "passed" } else { echo "failed" }'
Clear terminal on restart
You can chain the clear command (or the cls command if you're on Windows) so that the terminal is cleared before everything restarts. You will not be able to use the wgo run command, instead you'll have to use the wgo command as a general-purpose file watcher to rerun go run main.go when a .go
