Automatic rebuilding and running of Go apps on source file changes.
fresher is designed for use during development to remove the need to run go run each time a source code file is changed. Run fresher in place of go run and your binary will be rebuilt upon any .go file changes.
Run go install github.com/c9845/fresher@latest.
Run fresher in the same directory as you would run go run.
For more advanced usage, and customizing how fresher works, run fresher -init to create a config file in the current directory. The config file is pretty self-explainatory, however, see the config file description below for more details.
- The directory tree, starting where fresher is run, is traversed recusively.
- Each directory that contains at least one file with an applicable extension (i.e.: .go) is watched.
- When a file is changed,
go buildis run and the built binary is then run. This is repeated upon each file change.
fresher is a rewrite of github.com/gravityblast/fresh (previously known as github.com/pilu/fresh) to improve the configuration options, improve, modernize, and document the code base, and improve performance. You can use fresher in the same manner as fresh.
fresh's configuration file used a custom format.fresheruses YAML.fresher's configuration file is much easier to understand, use, and modify.freshdid not allow for using build tags.fresherallows for build tags via the GoTags configuration file field or the-tagsflag being passed through.fresh's configuration will not work withfresher. The configuration files are, however, somewhat similar and can be translated.
freshermodernizes the codebase using the latest third-party libraries, latest Go features and standard library, and implements Go modules.- Code documentation is immensely better;
freshhad near-zero code documentation. This should help with future development and maintance.
fresheris a bit faster due to reduced build delays and faster rebuilds when a file change occurs during an ongoing build (the ongoing build is killed infresher;freshwaited for the build to complete before rebuilding).- File changes on Windows are handled better; duplicate file change events are caught preventing needless rebuilds.
fresheruses one watcher goroutine instead of one goroutine per watched directory.
Create a configuration file with the fresher -init command.
Some configuration file fields can be overridden by flags to fresher.
- GoTags is overridden by
-tags. - Verbose is overridden by
-verbose.
| Field | Description | Default |
|---|---|---|
| WorkingDir | The directory fresher should watch for changes i. Typically, the root of your repository. |
. |
| EntryPoint | The relative path to your "package main" file based off of the directory fresher is being run from. If you have a "main.go" file in your local directory from which you are running fresher, you can leave this as ".". However, if your "package main" is in any other path, specifically a subdirectory of your repo, you must provide the relative path to it here (i.e: "cmd/app/app.go"). |
. |
| TempDir | The name of the directory off of WorkingDir that fresher uses for storing the built binary. |
"tmp" |
| ExtensionsToWatch | The types of files fresher will watch for changes. Typically just files used in a binary. |
[".go", ".html"] |
| NoRebuildExtensions | The types of files fresher will just rerun, not rebuild, the binary on upon a file change occuring. Typically this includes files that are read and cached by a running binary (for example, HTML templates via the html/template package), but not included in the binary. Caution if you use embedded files! |
[".html"] |
| DirectoriesToIgnore | Directories that will not be watched for changes, recursively. | ["tmp", "node_modules", ".git", ".vscode"] |
| BuildDelayMilliseconds | The amount of time to wait after a file change event occurs before rebuilding the binary. A delay is useful for catching multiple saves happening in rapid succession. You should not need to set this higher than 300. | 100 |
| BuildName | The name of the binary as built by fresher. This file is stored in TempDir. |
fresher-build |
| BuildLogFilename | The name of the log file where errors from go build will be saved to. This file is stored in TempDir. |
fresher-build-errors.log |
| GoTags | Anything you would provide to go run -tags or go build -tags. |
"" |
| GoLdflags | Anything you would provide to go build -ldflags. |
"-s -w" |
| GoTrimpath | If the -trimpath flag is provided to go build. |
true |
| Flags | Any flags your binary defines using flags package. |
"" |
| Verbose | If extra logging is provided while fresher is running. |
false |
Why not just use air (https://github.com/cosmtrek/air)?
In my testing and usage, fresh is much faster than air at responding to file change events and rebuilding/rerunning the binary. Although air is a more-or-less a fork of fresh, it does not improve performance. It seems like air is much "heavier" and there is more of a focus on tooling (for building air, i.e.: testing, CI, tools, etc.) rather than the underlying functionality.
The process of building then running was inherited from fresh. It isn't clear why this was done.
We assume the build & run method was used since:
- Then the entrypoint file (i.e.: main.go) does not need to be provided (
go run main.govs.go build). - Rerunning an already built binary is faster than running
go runif a file was changed that doesn't require a rebuild (see NoRebuildExtensions). - Possibly easier inspecting of build errors.
- Is
go runreally any faster thango build?
gofmtis required.staticcheckis required and must return no warnings.- Try to keep code style as similar as possible.
- Comment lines are ~85 characters long.
- All tests must pass.
- Total code coverage isn't of utmost performance, although raising coverage is nice.
- Performance is important. Performance (speed of recognizing file change events and rebuilding) should never degrade.
- Code comments/documentation should always try to answer "why" something was done. Expect the reader to not understand much.