First off, why an article on Backbone / Marionette / Ampersand? These libraries no longer capture the imagination of developers nowadays. However, a significant number of applications were developed with these libraries and many are still around! Our company has at least three projects still using this stack. During their normal development, we’ve upgraded the bundling mechanism from require.js to Webpack and have found enormous benefits, especially with hot reloading.
Many people assume that hot reloading can only be done using React. However, any project using Webpack can use hot reloading to super-charge your dev environment. I’ll show how you can enable this feature, and how you can use it in your Backbone/Marionette/Ampersand project. I’ll also explain what can be hot reloaded and what cannot.
What is Hot Reloading
Webpack Hot Reloading
It’s not too magical: Webpack builds a dependency tree of your modules as it builds them. If something changes, it can let you know if something you’re interested in has changed. It’s true, Webpack can’t magically know how your app is put together and what state it’s in, but if you give it some help or direction, you can do great things.
Webpack gives you an API that lets you accept any changes to an asset, re-require it, and then update your application accordingly. It might be best to start with an example.
So some things to note here:
- If you’re not familiar with Ampersand, it’s not too different from Marionette or Backbone. The renderWithTemplate is basically equivalent to
templateis a function. It also works with string only templates.
- We’ve got
templateproperties that are
requireing ‘.hbs’ files. We’re using handlebars templates which get compiled to functions. I’ve got a Webpack loader setup so that anytime you
requireing just a simple string, we’d configure a Webpack loader (the
raw-loader) to load up the file as a string.
Let’s hot reload
Let’s say that you’re working heavily on the ChildView. You’ve got your tests running but you also would like to see how new HTML would look as you change it as well as the behavior of the view. Let’s set it up for hot reloading.
All the hot reloading code is done in the initialize of the view, but it could be done anywhere. The interesting thing about this is that Webpack keeps track of anything that
ChildView depends on and will call our function when any of those things change. For example, if you update your .hbs file and add a new
<div>, our child view will be reloaded. If ChildView depends on and uses another different view and that view changes, then child view will get reloaded.
This can be an incredible productivity booster!
####Yeah but.. It sure seems like that’s a lot of code! Is all that going to be in my code base? First let’s try to refactor a bit:
Even so, we still have a
Optimization to the rescue:
At this point, as far as I know, you’re stuck with this piece of code in your project. But don’t worry, Webpack has a trick up its sleeve. Webpack can be aware of your development environment and your production environment. If you disable hot module reloading in your Webpack config and then optimize, that whole block of code just gets removed. How does it do this? Let’s look at how Webpack builds this bundle. If hot module reloading is disabled, Webpack will convert the
if(false) on one pass, and then since that’s always false, Webpack then removes that whole block on optimization. Bottom line, no extra code in your production system, but all the benefits of hot reloading in development!
Tips for happy hot reloading
In my experience it is best to add this code to a strategic section of your app you want reloaded. Don’t go overboard and make every view hot reloaded. Even with optimization removing extra code, you’ll still see it in your files, increasing cognitive load.
Along those lines, if a view has completely stabilized and is not being worked on, consider removing the hot reloading code for the same reasons (cognitive load). It’s easy to add it back later should you want it.
You may be tempted to try to abstract out the hot reloading to a separate mixin. I’ve tried this unsuccessfully and spent a lot of time doing so. If you do succeed, please share!
You will have the most success if you try to keep your views as stateless as possible. Your model should be holding most of your state. If you’re storing that state in the DOM or in your view, then your hot reloading block will need to be ‘smarter’ and try to transfer that state over when it rebuilds the hot reloaded view. For example, if you want to keep a checkbox checked on hot reload, you need to either have the checkbox state be derived ultimately from the model or stored somewhere on the view. Then when hot reloading, you need to grab that state from the view and re-apply it to the new view. Needless to say, this can be cumbersome and a good reason to go for stateless views.
This works best for views and their subviews. But as I said in the intro, you can hot reload almost anything, including controllers. The difficult part is building the logic to hot replace it in your app without making things blow up. But since Webpack gives you a place to do your own logic, it is definitely possible!
Using Webpack as a bundler brings a whole slew of benefits. React users have been enjoying hot reloading for a while, but if you’ve got a Backbone/Marionette/Ampersand application, you too can enjoy these benefits with just a little extra effort. The gains for your development cycle time are enormous! Enjoy!