Developer eXperience or DX is really important. Something that we use every day and almost forget is Hot Reload; in Ruby World, there is a cool gem that is appreciated: Spring for Hot Server Reload. So, in this article, we will see how to build a simple preloader in Ruby.
Polling
There are several techniques to achieve what we want. But the easiest one stays polling. Basically, what we will do here is create a watcher that polls over the files of our current directory. Then, our app will reload the files if necessary.
class Watcher
def initialize(files)
@relative_mtime = files.map do |file|
File.mtime(file)
end.max
end
def watch
mtime_max = Dir.glob("**/*").map do |file|
File.mtime(file)
end.max
if @relative_mtime < mtime_max
@relative_mtime = mtime_max
true
else
false
end
end
end
App/Server Reloading
Now we can build our app, this app is simple but it could be a Rails app.
Here, you see that at the beginning, we require
the Watcher
, then a test1
file, and a test2
file. But with a little subtle thing. the first one is done with require and the other one with load.
We are going to see why after.
require 'watcher.rb'
require 'test1'
load 'test2.rb'
files = Dir.glob("**/*")
watcher = Watcher.new(files)
while 1
Kernel.sleep 1
begin
Test1.test
Test2.test
rescue => exception
p exception
end
stale = watcher.watch
if stale
Dir.glob("**/*").each { |f| load(f) }
end
end
So now, if you change the test2
method, you will see the difference. But if you do so for test1
, it won't be reloaded. Using require
makes it impossible for you to reload this particular file.
This will also work with autoload, but you must remove the constant first.
Conclusion
Now you know how to make your own hot reload. And, of course, you can find the most effective way to do it.
The Spring Gem has 2 strategies if I am not mistaken. First one the simplest is Polling, otherwise, it uses the listen
gem developed by Thibaut Guillaume Gentil.