Rethinking Hot Module Reloading
I recently worked on the FuseBox module loader to make its Hot Reloading configurable. Before I jump into how that works here is a quick node / modules lesson.
Modules are just fancy globals
You might already know this as a seasoned developer but I’ve seen people of all levels being unaware of this fact too many times. Say you have
./foo.ts with the following
As soon as another file requires this one e.g.
require (or `import` in ES6) the same module you get the same copy. Even though
foo.ts twice, you will see
Executing foo only happen once. Essentially once a module is required … it is executed only once and then the
module.exports object is cached and returned on each subsequent
require. If any of this is still unclear, then I recommend reading a book on NodeJS (I wrote one as well) or even the official docs.
FuseBox default HMR
FuseBox has excellent docs. Checkout the ones on the LoaderAPI.
By default when a file is changed fusebox compiles it to a
.css and sends it down to any connected clients via a websocket as a
SrcChangedEvent. The client then uses the loader api to:
- Flushes all files from loaded cache using
FuseBox.flush. What this means is that when a file is required again … it will be executed again and there will be a new
- Patches the contents of the file that is updated with the contents as passed in with the
- Executes the
mainPathfor the current default package again. Since all modules are flushed everything essentially executes again as it gets required again from the
As an outside reviewer this behaviour feels absolutely beautiful. If your application is always an output of some state, it *should be able to be re-rendered in its entirety* using this behaviour just fine.
But your application likely has some modules that you don’t want running again and being reused between HMR updates. Fortunately FuseBox HMR provides loader plugins that can completely change the behaviour to whatever you want!.
Things you don’t want running again
I call these
stateful things. An example is a router that registers a hook on
window.addEventListener(“hashchange”,/*something*/) is not something you want executing again:
Similarly for things that initialise state:
You can write a function that adds a loader plugin, which will change the hmr update behaviour to be:
- if something
- flushes all files from loaded cache except stateful ones
- patches the changed files on HMR update
- runs the application entry point again
- if something
- refresh the whole window
This way you don’t get duplicate global handlers and get to reuse state without needing to wrap your components in anything fancy.
Fortunately you don’t have to write this function as the FuseBox team was happy enough to ship it with the core! Just bring in
fuse-hmr as shown below:
Here it is in action
Footnote: Why fusebox?
It’s insanely fast. It’s generally the first reaction
But the thing that got me was really the approachability of the source code. I’ve ranted a bit on the value of typescript and here is a recent post by someone else that’s very well written. You won’t find much code here for the sake of catching user errors that can caught at compile time (thanks to TypeScript). It’s all open source so go ahead and have a look, adding your 🌟 while you are there.
Its built with TypeScript and supports it out of the box. In fact your config even autocompletes if you write it in ts (tip: use
ts-node to run it):
Also its API first instead of using config files. Means you can use it as powerfully as you want 🌹
If you liked this post / ideas don’t forget to hit the green heart 💚