This is a sequel for the Journey From RequireJS to Browserify post.
After publishing the previous post I got a lot of feedback saying that Browserify can’t do asynchronous module loading. Since that’s something I’d like to have with Browserify too I started looking on how to do it and after couple of pull requests and one published npm module later I’m happy to say it’s very much possible now!
Basically asynchronous module loading can be done just by creating multiple bundles with Browserify and loading them with a script loader of your choosing. There is one in jQuery or if you don’t like jQuery there are quite a few standalone ones out there.
This is a simple use case and it has almost nothing to do with Browserify. For
example if we are using
Function.prototype.bind in our app and we want to
load es5-shim if the browser is missing the implementation:
1 2 3 4 5 6 7 8 9 10 11 12
To detect modern enough browsers for Zepto we check for
To do this we need to build simple lightweight entry point with a script loader and two versions of the main bundle. One with Zepto and one with jQuery.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
In index.js we just detect which one we want to use and load it:
1 2 3 4 5 6 7 8 9 10 11 12 13
In our app code we need to abstract the require calls to jQuery and Zepto to make it smooth:
1 2 3 4 5 6 7 8 9 10
And in app code just use
var $ = require("./jquery-or-zepto"); to get the
correct one depending on the bundle we loaded.
Now this is where things get really interesting.
Lets say our app has some graph view which requires a large graphing library and we want to load that library and related code lazily only when the user actually uses the feature like this:
1 2 3 4 5 6 7 8
To do this we have to remove the
./graph-view and its dependencies from the
main bundle. Here’s where my module, externalize, comes to help.
We create a second Browserify bundle which is a subset of the main bundle and
externalize function to remove code from the main:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
Now just include
./bundle/main.js to the page and
be loaded lazily when needed.
Checkout the externalize readme file for more information.
I’ve uploaded a more real worldish example on github pages using the techniques presented here. It will also serve as a decent Backbone.js and Handlebars example with Browserify. It’s heavily commented so it should be easy to follow even if you don’t know/care anything about Backbone or Handlebars.
Open up devtools from your browser and look at the network tab to see what happens when you hit to “Toggle graph” button for the first time.
I encourage you to read the source code of the example in following order:
- Build script for the bundles
- This is the first thing executed on the page
- It determines whether to load jQuery or the Zepto version of the main bundle and whether to load the shims
- The actual application code starts here
- It lazy loads the graph code on first time it is used
- Compiled bundles
- Take a look at their sizes and skim through what they contain