Hot Reloading Done Right!
When I first learned how to program, compile and execute my code, I ran into a frustrating problem: hot reloading. The idea of seeing changes immediately after saving is crucial in web development, as you make frequent changes and want to see the results as quickly as possible. It's also essential in game development, where you tweak variables and want to observe the effects instantly. While it's possible to use the compile command and run the executable with an IDE, I don't use IDEs in my workflow.
I use Neovim, by the way.
In my quest to find a solution that meets my development needs, I discovered several CLI tools that enable hot reloading for any program, any compiled programming language, and in any code editor. All you need is the build command, the directory where the executable resides, and some simple CLI tools. I'll do my best to explain each tool and how they work together.
Before we dive in, I want to clarify that there are many ways to solve this problem. My solution might not satisfy your needs, but it works on my machine, and I haven't seen a similar setup online, so I'm sharing it.
CLI Tools
I prefer tools over programs because I don't want to install a complex program with weird configs just to add hot reloading to my app. Some programs didn’t even work on my machine.
I'm using macOS, a Unix-based system. Things might differ on other platforms, but the process is pretty much the same on Linux (apart from tool installation).
-
GNU Make: A build automation tool that gets its knowledge from a
Makefile
. You can define sub-commands likeinit
,build
, orclean
, and run them withmake
(e.g.,make build
). -
find: A powerful file search utility that helps us locate the files we want to watch for changes. It's more flexible than
ls
. - entr: A simple utility for running arbitrary commands when files change. This is the magic ingredient for hot reloading.
Makefile
After installing the tools, we can start writing the Makefile
.
- Create the file with
touch Makefile
. - Open the file in your editor (I use Neovim). Syntax highlighting is optional but helpful.
- Depending on your project and programming language, you’ll need the compile command and the path to the executable. For this tutorial, I'll use C and the
gcc
compiler.
The C Program (for demonstration):
#include
int main() {
printf("Hello from @MoreThanCoder\n");
}
To compile this, I’ll use gcc -o main main.c
, which creates an executable named main
in the current directory.
Basic Makefile
:
build:
gcc -o main main.c
.PHONY: build
The .PHONY
line ensures that make build
is always executed, even if a file or directory named build
exists.
Add a run
Command:
build:
gcc -o main main.c
run: build
@./main
.PHONY: build run
The run
command depends on build
, so it will automatically trigger make build
and then execute the program. The @
symbol suppresses the command output.
Add the Watch Command:
build:
gcc -o main main.c
run: build
@./main
watch:
@find . -name "*.c" | entr -r make run
.PHONY: build run watch
The watch
command uses find
to search for all .c
files and pipes the output to entr
. The -r
flag tells entr
to restart the program when files change. When you run make watch
, your program will rebuild and execute automatically upon saving changes.
Bonus for Web Devs
If you're a full-stack web developer, dealing with server restarts and browser refreshes can be painful. Here's a simple solution:
async function isAlive() {
try {
const res = await fetch('/ping', { cache: 'no-store' });
return res.ok;
} catch (error) {
return false;
}
}
async function monitor() {
let restarted = false;
while (true) {
const alive = await isAlive();
if (!alive) {
if (!restarted) {
console.debug("Server is down, waiting for recovery...");
restarted = true;
}
} else if (restarted) {
console.debug("Server is back alive, reloading...");
location.reload();
break;
} else {
console.debug("Server is alive.");
}
// Adjust the timeout based on your server restarting time
await new Promise(r => setTimeout(r, 400));
}
}
monitor();
This script pings a /ping
route on your server. If the server goes down and comes back up, the script reloads the page. Add this to your HTML in development mode for a seamless experience.
Summary
We learned how to create a custom file watcher with hot reloading using make
, entr
, and basic Unix tools. If you found this helpful, support me with likes and subs to my YouTube channel.
Follow me on Telegram or GitHub.
Have a good day!