Module loader comparison: Webpack vs Require.js vs Browserify

Choosing the right module loader is an important decision for any high quality web application. You don’t want to add script tags manually into the html because is not scalable (you have to manually order, no deploy minification…).

The final decision is WebPack, and the following text explain the rationale behind.

The main requirement for a module loader is to allow to write environment agnostic (or isomorphic) code. This means that the same code (in this case physical file) will both run in node.js as well in the browser.

Each module loader implements the server support differently:

  • Require.js and WebPack: has a little helper to use on server;
  • Browserify: needs none because works out of the box;

KIIS FM's 2012 Jingle Ball - Night 2 - Show

Module code style

With require.js the modules will look like this:

define(['a', 'b'], function(a, b){return {myModule: 1}})

or when you need many dependencies you will find yourself in a mess so you will do this:

define(function(require, exports, module){
    var a         = require('a');
    var b         = require('b');
    module.exports = {myModule: 1};
})

Both variants are not optimal, because of the extra code.

With WebPack and browserify your module will look like this:

var a          = require('a');
var b          = require('b');
module.exports = {myModule: 1};

Which looks exactly like native node.js modules.

The votes are:

  • WebPack: +1;
  • Require.js: -1;
  • Browserify: +1;

BrantaLeucopsisMigration

Migration

You can migrate from any style to webpack. For example I’ve been using require.js style modules and moved to webpack seamlessly. It was fast and quick because I had no need to make any change to any source file (with exception to the configuration of the build process). Then slowly I’ve been upgrading to the webpack way. No votes for this point, but webpack shines again if you already have a big project under the hand (+1000 files).

k-bigpic

Aliases

Aliases are extremely important because keeps your code well organized, clean, robust and easy maintenance.

WebPack and require.js both have aliases both on client and on server side.
With browserify this is not possible because has no support to do that on node.js. If you manage to make aliases work in the browser those will not work in node.js.

Why is this important. Let’s see this code structure:

  • src
    • client/someFolderA/a.js
    • shared/logic/complexLogic.js
    • server/someFolderB/b.js

Now you are coding something in server in the file “server/someFolderB/b.js”, how would you load the “complexLogic.js” file?

Without aliases is a mess already:

// From file "server/someFolderB/b.js"
require('../../shared/complexLogic');

This is not optimal. Some real world examples: ghost1, ghost2, ghost3 with 3 levels, material-ui, strider1, strider2;
Now let’s say that you move the “server/someFolderB/b.js” file to another dir, you will have to update all the relative paths (sometimes is good to have relative paths, but you need to know when to use them).

With an alias you do this:

// From file "server/someFolderB/b.js"
require('shared/complexLogic');

You have to add an alias named “shared” to “src/shared”. This is cleaner and more robust.

The browserify users can do something similar but is not optimal. They can add the root project to a folder named “node_modules”:

  • app
    • node_modules
    • client
    • shared
    • server

This is good if you only need 3 root aliases and you don’t mind about that “node_modules” folder in your app. Is not intuitive to new developers because they would expect only node modules into the “node_modules” folder, but is not a really big deal anyway.

The votes are:

  • WebPack: +1;
  • Require.js: +1;
  • Browserify: -1;

speed

Speed

In development mode no benchmarks have been done, but from personal experience the faster between the 3 is require.js because doesn’t need any pre-process task before running.

The build process speed is determined by 2 variables:

  • The task runner (gulp or grunt);
  • The tasks ran (webpack, browserify or require.js);

Gulp is by far faster than grunt. No stats have been done to compare all the options.

The votes are:

  • WebPack: 0;
  • Require.js: +1;
  • Browserify: 0;

1369847707_4085_memory

Memory used

Both webpack and browserify uses a lot of RAM because have to keep all the application source code in memory. Require.js is the lightest of all, because no code has to be kept in memory.

The votes are:

  • WebPack: 0;
  • Require.js: +1;
  • Browserify: 0;

1254991_Integration (1)

Integration with other modules

Loading modules from bower requires to be shimmed in require.js (don’t know about browserify). With webpack all this is almost automatic with the exception of some outliers.

The votes are:

  • WebPack: +1;
  • Require.js: -1;
  • Browserify: 0;

Paiute_Deadfall_Trap

Webpack caveats

Using enhanced require (to make webpack work on node.js) with node.js you might find some problems such as:

  • Loading the java module because is binary (easily fixed by requiring with the original node.js require method);

The votes are:

  • WebPack: -1;
  • Require.js: 0;
  • Browserify: 0;

Conclusion

From this review about webpack, browserify and require.js you can better understand what are the cons and pros of every tool.

The final votes are:

  • WebPack: 2;
  • Require.js: 1;
  • Browserify: 0;

Between all the choices available is strongly suggested to use webpack with gulp.

Comments on twitter: