Skip to content

sophic00/reload

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

23 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

reload

A language-agnostic hot-reload CLI tool. Watches your source files, rebuilds on changes, and restarts the server automatically. Works with any project that has a build command and an executable to run.

Installation

go install github.com/sophic00/reload@latest

Or build from source:

make build
# binary is at ./bin/reload

Quick Start

# Go
reload --root=. --build='go build -o ./bin/server ./cmd/server' --exec='./bin/server'

# Rust
reload --root=. --build='cargo build' --exec='./target/debug/myapp' --include='*.rs'

# TypeScript
reload --root=. --build='npx tsc' --exec='node dist/index.js' --include='*.ts'

Edit any source file, save, and the server is rebuilt and restarted automatically.

Architecture

The tool is a channel-based pipeline with four stages:

filesystem events ──> watcher ──> debounce ──> builder ──> runner
                     (fsnotify)    (200ms)   (sh -c build) (sh -c exec)

Watcher recursively watches directories using fsnotify, filtering by include/exclude patterns. Directory events always pass through so new files in subdirectories are detected.

Debounce coalesces rapid filesystem events (editors like vim emit write+rename+chmod per save) by resetting a timer on each event and only firing after the configured quiet period.

Builder receives change signals, cancels any in-progress build (SIGTERM first, SIGKILL after grace period), drains stale signals, and starts a new build. Each build gets a trace ID for log correlation.

Runner stops the previous server process with graceful shutdown (SIGTERM, then SIGKILL after timeout), starts the new one, and detects crash loops (exits within a threshold) by applying a cooldown before restarting.

Stages communicate via capacity-1 buffered channels (chan struct{}), meaning "at least one event happened" without blocking the producer.

Project Layout

main.go                 entrypoint
internal/
  cli/                  flag parsing, config resolution, signal handling
  config/               3-tier config (defaults < TOML file < CLI flags)
  reload/               pipeline orchestration
  watcher/              recursive filesystem watching
  builder/              build command execution with cancel/restart
  runner/               server process lifecycle management
  logger/               structured logging with ANSI color support

Configuration

Configuration follows a 3-tier precedence: defaults < config file < CLI flags.

CLI Flags

--root              Project directory to watch
--build             Shell command to build the project
--exec              Shell command to start the server
--include           File patterns to watch, e.g. "*.go,*.html" (default: all)
--exclude           Paths to exclude from watching
--config            Path to a TOML config file
--debounce          Debounce delay before triggering a rebuild (default 200ms)
--build-grace-period  Grace period for build cancel before force kill (default 3s)
--shutdown-timeout  Timeout for graceful server shutdown (default 5s)
--crash-threshold   Max uptime to consider an exit a crash (default 3s)
--crash-cooldown    Cooldown before restarting after a crash (default 5s)
--no-color          Disable colored log output
--log-json          Output logs in JSON format
-v, --verbose       Enable debug logging

Config File

If no --config flag is given, the tool looks for config.reload.toml in the current directory. See example.reload.toml for a fully commented example. To use it, copy it into your project:

cp example.reload.toml config.reload.toml

CLI flags override any values from the config file.

Key Design Decisions

Process group management -- Both build and server commands run in their own process groups (Setpgid). Signals are sent to the entire group (kill(-pid, ...)), ensuring child processes don't leak.

Auto-exclusion -- The exec binary (parsed from --exec) and the config file are automatically excluded from the watcher to prevent infinite rebuild loops.

Graceful shutdown -- SIGTERM is sent first, with a configurable timeout before falling back to SIGKILL. This applies to both build cancellation and server restarts.

Crash detection -- If the server exits with a non-zero code within crash_threshold, the runner waits crash_cooldown before restarting to avoid a tight restart loop.

NO_COLOR support -- Respects the NO_COLOR environment variable in addition to the --no-color flag.

About

Live reloading engine written in Golang

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors