A Journey From Require.js to Browserify

A couple of years ago I started developing Echoes Player with Backbone.js, Underscore.js, Bootstrap and Require.js. Recently I migrated the code to use browserify, and i'd like to share the insights from this process.

Preface

Back then, I saw require.js as a solution for dependency management with javascript. Later on, while not using the lazy loading ability, I took the chance of creating a build file for whole project - concatenating all the js files to one uglified & optimized file. In the land of Backbone.js development and code organization, require.js gave the ability to implement the separation of concerns, and promoting good code practicing by creating separated files, load them to a module (let it be lazy or not) and have a sane maintenance of code.

Require.js has support both for the AMD & CommonJS specs for module definition as well as for loading incompatible files with these specs.

AMD syntax uses a function which wraps the module definition with whatever you choose to load. It uses a return value as the exported features  of this module.

 

CommonJS syntax uses the require syntax and exports modules features using the "module.exports" syntax. Node.js uses the CommonJS spec for module loading.

 

The Pitfalls

Overtime, The code of Echoes player started to grow big, so some modules might have to load few files. Some code became hard to maintain. I got tired of using the double variable names for syntax:

Looking up where this module came from in a big list was tedious and hard.

The build process, r.js, was and is still great for the purpose of Echoes Player project. I created aliases, css optimization, dependencies, special build options and optimization. You can checkout the configuration I used recently in all of the builds.

I didn't use all the options. One feature I wasn't able to use was the sourcemaps option and using uglify 2 for minifying.

Enter Browserify

I started experimenting with node.js during the last year, and I really got used to the simplified and minimal form of requiring modules, using them and export the relevant features you want.

Then Browserify published.

Browserify In a Nutshell

Node.js style in your browser. Suddenly, the code of Echoes started to shrink, or at least, in various cases, became much more maintainable.

Browserify's website has a very long list of articles, how to's and more resources its github page.

Using the CommonJS style makes more sense to me than using the AMD. I was hooked and started to convert all the code of Echoes to use CommonJS style. Require.js does has support for this style, however, the code has to be wrapped in a function and a server has to support the lazy loading feature.

Browserify has plenty of features aside from using the CommonJS style (there's also support for AMD with browserify transforms). It gives you the option to use any node.js modules in side the browser. Basically, I can use the same Backbone.js package in the backend and in the client.

Build Process

Another neat feature of browserify is its build options. Browserify is a command line utility, and aside from all of its abilities and options, it creates one big concatenated file of all the js files that are required in the main file that has been processed by it. For this process, it can get various options which will influence the end result. Some of these are: Sourcemaps and minify.

The project still had few challenges that I had to solve:

  1. Find a way to use aliases with browserify
  2. Using "shims" for loading CommonJS in compatible files (i.e. jquery-ui)
  3. Automate the process of compiling changed js files
  4. connect the flow to a grunt build system

Browserify with Grunt

In Echoes, I currently use Grunt.js as build system. So, solving out the challenges above was quite easy once i've found the grunt-browserify plugin. Using and configuring  backbone.js was a little bit tricky since with the CommonJS version of Backbone.js, you should specify the Backbone.$ / jQuery - so I had to define the $ method manually

However, that turned out to be well fit into the overall picture, since i also needed to have support for the backbone extension manager I developed back then - Backbone.Beamer.

Transformations

[UPDATE 26/09/2014] While Require.js has the concept of plugins, Browserify has the concept of transformations. It Is Awesome.

You can configure a list of transformation that code should pass through before the end result is written to the destination file. It's like filters in cameras. You still get result, after it has been digested by the filter. There's a huge list of transformations in browserify's github wiki

Since Echoes Player uses underscore templates and require.js to load these (html files), I found a this great jstify transform which does 2 important tasks:

  1. it allows loading html files with underscore template annotations, with the require method in js (awesome 1) - that can be done with require.js text plugin.
  2. it gives the option to precompile these templates, which will save computation time in the client (awesome 2).

Closing Notes

To summarise, the transition to using browserify turned out to be a nice experience with CommonJs style, leaving a more simple roadmap to migrate the build system to gulp.js (at least, I intend to) and a great reminder to keep programming & developing in a modular style.

[UPDATE 26/09/2014] This article reflects my own personal thoughts of working with modules and dependency management in javascript as well as challenges and interests in new solutions.

Currently, Echoes code with browserify is in its own branch. go ahead - it's open source.

  • Pingback: A Journey From Require.js to Browserify | #Code...()

  • Doron Zavelevsky

    Very nice – thanks for sharing!

    Worth mentioning some trivial stuff – like the fact that browserify runs into some troubles with certain node modules – and of course anything that involves the file system.

    However – usually after few touch-ups it’s a pretty smooth ride.

  • hi Doron.
    you’re right. I didn’t dig too much into using nodejs modules – however i did read about several modules that works only in node.js runtime.
    Thanks for sharing 🙂

  • Pingback: Issue #19 – Sept 26th 2014 | Tales from the Front End()

  • You don’t have to use double variable names,

    define(function(require) {
    var $ = require(‘jquery’),
    Backbone = require(‘backbone’),
    FooterView = require(‘views/footer’),
    HeaderView = require(‘views/footer’),
    return Backbone.View.extend({

    });
    });

  • steve mao

    Typo: Using the CommonJS style makes more sense to me ‘then’ using the AMD.
    should be ‘than’

  • @disqus_Z68EIRjnCr:disqus Thanks. fixed.

  • For one thing, you don’t need to import jQuery and Underscore if you aren’t explicitly using them in the module. If you’re loading in Backbone, it should already be loading them as dependencies, so that 1st example could easily have 2 dependencies removed, which would shorten your lists.

    Also, RequireJS has a tpl plugin (https://github.com/ZeeAgency/requirejs-tpl) that is way better than the text plugin because it automatically runs the Underscore templating function on it, and when you build using rjs, it precompiles the templates for the build.

    I’m not trying to convince you to come back to RequireJS or anything, I just don’t want people to feel like it is being blown out of the water by Browserify. Browserify certainly has some very cool things that it does better than RequireJS, but it also works the other way around. You can start up a RequireJS prototype app more quickly because it doesn’t need a build step. Also, it can do lazy loading, which you obviously know. In the end, you ought to be having a build step anyway and most apps don’t use lazy loading, so RequireJS doesn’t tend to win out. And people like the CommonJS syntax better.

    Personally, I like the ES6 module syntax and I’m excited to see more build tools working off of that and adding plugins and/or transformations.

  • hi @JoeZimJS:disqus.
    As for the jquery & underscore part – that’s a good point and you’re right.
    However, there are some modules where i use jquery and underscore explicitly in the module (i.e., a Backbone.View module) – and that’s why they are required. I prefer not to rely on the global namespace of underscore and jquery and rather require those in case a module needs them.

    Starting up a requirejs project more quickly might be correct if you’ve already worked with require.js and setup the configs, shims and other as needed. From my perspective, starting to use browserfiy with auto building for each change in files feels quicker – only 1 short command line with browserify and watchify installed..

    However, In today’s development era, you can choose to start up a project from a variety of boilerplates forked form github or scaffold one with Yeoman – where the build process is already integrated inside.

    I’m also excited by some of the new ES6 features and hope to work fully with it soon.

    Thanks.

  • Boris Kozo

    You mention “migrate the build system to gulp.js”. What is the reason to do it if you have a working Grunt build system? What would be the benefits of migrating?

    I am asking because my project has a pretty elaborate Grunt based build system and I keep hearing of people migrating (which in my case may take at least a week) to Gulp but never give a good reason why (i.e. “Its cool and trendy” is not a good reason for me).

  • hi @boriskozo:disqus
    my purpose in migrating the build system of Grunt to Gulp is:
    1. getting to know gulp better
    2. having a comparison in performance between the 2 builds for the tasks
    3. simplifying the build process – in terms of creating separated tasks more easily as well as not having to created temp files (as in grunt) but work on streams (as in gulp).

    Thanks.

  • q
  • Pingback: CommonJS, RequireJS, Browserify and AMD explained | No Bug Life()

  • EthanB

    Use the “brfs” transform to embed files into your bundle: https://www.npmjs.com/package/brfs

  • varun

    thats what i was looking for…thanx a ton for taking away my pain..

  • Pingback: ??browserify??JavaScript???? | My blog()

  • Pingback: Javascript Weekly No.200 | ENUE Blog()