Browserify and ReactJS

Entering into using Browserify for the first time demands an answer to an important question — What is Browserify?

Browserify simplifies dependencies management and usage of your Javascript application by utilizing commonJS import formats (require('modules')) and bundling them with your app for deployment. It’s kind of funky to say, and yes several times I referenced it as browserfy, omitting the i. There are other similar products (RequireJS), but this utilizes the node module syntax of module.exports instead of using AMD.

How do I Browserify?

The easiest way to get started is to follow the tutorial on their website. First, install using npm:

npm install -g browserify

Require-ing Dependencies

How browserify looks for required modules:

  • require('bar') – will look in your node_modules directory
  • require('./bar') – will look in the current directory
  • require('../plugins/bar') – will look in the relative path

Note: If you are migrating to using Browserify from another mechanism, you may want to use node to manage these dependencies. For example, instead of storing a versioned jquery library in your repository, you can update your package.json to include “jquery” : “2.1.1” as a dependency. It will then install in the node_modules directory when you run npm install.

Browserify and ReactJS

For our use case, we intend to utilize Browserify within a ReactJS application. Our usage of React kept classes isolated in JSX files, and compiled and used in the UX. Here is an example of a class:

define(["react"], function (React) {
  return React.createClass({
    //************ Meta Data **************//
    displayName: "MessageDisplay",
    propTypes: {
      message: React.PropTypes.string.isRequired,
    },

    //************ Render **************//

    /**
     * Render the loading component.
     *
     * @return {object}
     */
    render: function () {
      return (
        <main className={"container message-display"}>
          <p>{this.props.message}</p>
        </main>
      );
    },
  });
});

And used by:

define(["react", "component/MessageDisplay"], function (React, MessageDisplay) {
  React.renderComponent(
    MessageDisplay({ message: "Welcome back!" }),
    document.getElementById("box")
  );
});

Now, the class is add to the module.exports:

var React = require("react");

module.exports = React.createClass({
  //************ Meta Data **************//
  displayName: "MessageDisplay",

  propTypes: {
    message: React.PropTypes.string.isRequired,
  },

  //************ Render **************//

  /**
   * Render the loading component.
   *
   * @return {object}
   */
  render: function () {
    return (
      <main className={"container message-display"}>
        <p>{this.props.message}</p>
      </main>
    );
  },
});

and used by:

(function () {
  var React = require("react");
  var MessageDisplay = require("./components/MessageDisplay");

  React.renderComponent(
    MessageDisplay({ message: "Welcome Back!" }),
    document.getElementById("box")
  );
})();

Grunt integration

To integrate Grunt with Browserify, include the grunt-browserify plugin in your package.json, and update your Gruntfile.js with:

browserify: {
    dist: {
        files: {
            // all files to put into the bundle
            'bundle.js': ['<%= config.app %>/js/main.js'],
        },
        options: {
            // options passed to browserify
            browserifyOptions : {
            debug: true // create source maps
            }
        }
    }
}eibcccunbgvtkefgrgdlbvkrlebdvbeghfljllflgfie
eibcccunbgvtjgcbuhivrldjktdckbjvibnikcdvgudf

The plugin will pull all required files as well, so you don’t need to specify them all if you have only a single access point to your application. If you have multiple pages with varying content, you can create multiple output files and include each unique bundle (“account-bundle.js”, “help-bundle.js”, “game-bundle.js”, etc.).

I’ve also included the options for generating source maps, which map the lines within the compiled code to the original file and line, invaluable when trying to hunt down a bug!