Why we switched to webpack away from browserify

This article is gonna show you the reason for me to switch from browserify to webpack to build a major client-side web application.

Introduction

I’ve already started playing around with AngularJS and ReactJS quiet a while ago. Back in the days I was using browserify to optimize my application and combine it all in one single JavaScript file to serve it to the user very fast. This works very great for my small test projects.

Recently we started a new project at work to create a management platform with ReactJS and I started thinking about the size of the project. The problem was that the project itself is not longer just a couple of lines of code. It is now a large application with different modules where most parts a user will never see during a session.

First try browserify

At the beginning of that project I was playing around with browserify and found directly the first issue. The question if you can get hot reloading with ReactJS and browserify working. Thanks to livereactload I found a solution that can do this.

But then after going further into the project I was thinking more and more about the foot print a user has to download before he/she can really work on the site. For a huge project the user might have to download 3+mb of JavaScript even the user is just gonna use 200kb out of it with the operations the user is doing.

A first solution with browserify

Of course we can work around that by creating multiple modules. Each core area gets an own bundle build. But this requires us to send all the shared modules too (e.g. ReactJS). In addition to that we need to build that module loading our self. So it is not a very good approach if you wanna save yourself some work.

Welcome webpack

Every time you look for browserify you gonna hear about webpack too. Instead of just doing one task (building JavaScript modules for the browser). Webpack has more features including asset pipelines. So why are we looking now into webpack you might ask. Because webpack has a very cool feature called code splitting.

To define a code split point we just need to have in our code one or multiple code pieces like this:

require.ensure([], function(require) {
    var a = require("module-a");
    var b = require("module-b");
});

The cool thing is now webpack can detect this code when parsing all your JavaScript files and creates a separate bundle for each. So in this case it gonna create a bundle that has module-a and module-b. And as soon as the require.ensure is getting executed webpack is taking care of loading that dependency module and as soon as the callback function gets called that two modules are loaded and the require will resolve them correctly.

Isn’t that cool?! You don’t need to worry about lazy loading of modules. Or manual creating the sub modules. And the best thing is, if the module is already loaded webpack will use the already loaded modules instead of re-requesting the submodule.

But don’t we still have the problem with duplicated code within the modules? Yes this could still happen. Imagine two sub modules are using the same react-bootstrap components.

Lets optimize webpack

Lucky for us there is a plugin called CommonsChunkPlugin. This plugin analyses all modules within your application and extracts everything that is duplicated into one common module.

The only thing you need to do is to add the following snippet to your webpack configuration plugins section:

new webpack.optimize.CommonsChunkPlugin(/* chunkName= */"vendor", /* filename= */"vendor.bundle.js")

that’s it. Now the most commonly used parts of your application are getting extracted to a vendor.bundle.js.

What about server site rendering?

Now you might ask yourself what if I want to support server site rendering? NodeJS does not understand require.ensure. But that problem is very easy to fix. Just put the following code at the beginning of every file where you are going to use require.ensure:

if (typeof require.ensure !== "function") require.ensure = function requireEnsure(d, c) { c(require); };

Webpack is ignoring this code and the code extraction is getting applied without any problems. But if the code is executed with NodeJS we just define this function to be a synchronized function. Instead of waiting for the callback (and asynchronous loading of the dependencies) we just call the callback directly and passing in the regular require function.

Conclusion

A switch to webpack can help you to reduce the amount of code a user has to download first which results into a way faster page startup time. In addition the easy to use syntax to define splitting points helps you to keep your code easy and clean. Let me know what features you use for webpack!