Bring CommonJS to your asset pipeline
… and check why 5600+ Rails engineers read also this
Bring CommonJS to your asset pipeline
A few weeks ago, Marcin recommended Gulp as the Rails asset pipeline replacement. Today I am going to tell you how you can benefit from CommonJS modules in your Rails application with asset pipeline enabled.
You don’t have to disable asset pipeline in your Rails application in order to use CommonJS module loading in your JavaScripts. One of tools that allows you to do so is Browserify and a nice gem called browserify-rails
. It lets you mix and match //= require
directives from Sprockets with require()
calls in your JavaScript (CoffeeScript) assets. You can manage your JS modules with npm
, so you can use a wide variety of existing node modules, including React directly in your Rails assets.
Getting started
To get started, you need to have node
and npm
installed on your development machine and include browserify-rails
gem in your Gemfile
.
gem 'browserify-rails', '~> 0.9.1'
Then you should initialize your package.json
file using
$ npm init
in your’s application root directory and add the following packages to your dependencies:
$ npm install --save 'browserify@~>6.3'
$ npm install --save 'browserify-incremental@^1.4.0'
That’s all! You can now start writing your CommonJS modules and use them in your Rails application.
// add.js
module.exports = function (a, b) { return a + b }
// application.js
var add = require('add');
console.log(add(1, 2)); # => 3
You can also install more node modules and require them in your assets:
$ npm install --save react
// application.js
var React = require('react');
React.render(React.DOM.h1(null, 'Hello world!'), document.body);
BTW, in our Rails meets React book, we’re also using asset pipeline to use React components in Rails.
Using browserify-rails
does not force you to use only CommonJS-compatible libraries. You can still use //= require
directive to load arbitrary JavaScript assets.
Configuration options
After installing browserify-rails
you are starting with default configuration that makes some assumptions:
- you store your JS modules only in
/app/assets/javascripts
and/node_modules
directories - you don’t want to generate source maps
- modules from
node_modules
should not be re-evaluated on page load - browserify is run only on JS files that have defined modules via
module.exports
or require some other modules withrequire
NODE_ENV
is equal to yourRails.env
You may tune up your config if you need. I would recommend enabling source maps generation in development environment for easier debugging. To do so you need to add the following line to your config/application.rb
file:
module MyApplication
class Application < Rails::Application
# ...
config.browserify_rails.source_map_environments << 'development'
end
end
If you are using CoffeeScript, you should follow .js.coffee
naming convention, install coffeeify
plugin:
$ npm install --save 'coffeeify@~>0.6'
and enable this plugin by adding the following line to your config/application.rb
:
config.browserify_rails.commandline_options = '-t coffeeify --extension=".js.coffee"'
Now you should just restart your server and write your assets in CoffeeScript flavour.
browserify-rails
supports the same features as node-browserify
, e.g. you can have multiple bundles. You can read about all possible configuration options on browserify-rails
github page.
Deployment
In order to deploy your assets to production server, you don’t need anything but running rake assets:precompile
task. If you’re running that task on your production server during deployment (e.g. when using capistrano
), you also need to make sure you have node
& npm
installed on your production. You should also install all npm dependencies before compiling your assets. You may use rake tasks provided by browserify-rails
gem to do so:
rake npm:clean
- this task would clean all installed node modules (it performsrm -rf ./node_modules
)rake npm:install
- this installs all dependencies by runningnpm install
rake npm:install:clean
- this combines two previous tasks by runningnpm:clean
andnpm:install
Final words
Using browserify-rails
can significantly increase modularity of your JavaScript assets, but have also some disadvantages.
Pros:
- you can use almost any node package directly in your Rails application through your asset pipeline
- you don’t have to stop using
//= require
directive for non-modularized assets - you have support for generating source maps
- you can have multiple bundles and mark some libraries shared between bundles with
--require
or--external
- this helps you to reduce size of the bundle, because you don’t need to include the same library more than once
Cons:
- you have to install
node
andnpm
on your development machine and on your production (if you are compiling your assets during deploy) - browserify compiles only JS assets, so you cannot use stylesheets from node packages
Summary
Using browserify-rails
may be a good option when you want to use asset pipeline and improve modularity of your JS assets. I think you may definitely give it a try!
Bonus: Heroku support for Browserify
Heroku is a very popular platform for deploying Rails applications. By default, it automatically determines how to build your app during deploy by using some heuristics (e.g. it assumes you have Ruby application if your root directory contain Gemfile
). In order to use browserify-rails
and run bundle
along with npm install
on target machine, you need to use a custom buildpack - heroku-buildpack-multi
. To use it, you will first need to set it as your custom buildpack by running the following command:
$ heroku buildpack:set https://github.com/heroku/heroku-buildpack-multi.git
Then you should create special file .buildpacks
in your application’s root directory that contains the list of all (ordered) buildpacks you would like to run when you deploy. In our case it would contain the following buildpacks:
$ cat .buildpacks
https://github.com/heroku/heroku-buildpack-nodejs
https://github.com/heroku/heroku-buildpack-ruby