CommonJS for Ruby on Rails
This blog post is for those who feel that Sprockets is not enough to structure the JavaScript code in a Ruby-on-Rails app. If you’re not satisfied with the #= require
and window.Global
mess, come under the cut.
Alternatives at hand
As you might suggest, the JavaScript community knows a lot about structuring large apps. Here’s a great overview of what the community can offer. In two words, the main practical alternatives are CommonJS and asynchronous module definition (AMD). Instead of considering the pros and cons of each approach, we’ll focus on CommonJS. It’s very simple and a solution of choice for Node.js, by the way.
If you’d like to know other people’s opinion, explore the limitations of the AMD approach and learn about AMD advantages over CommonJS modules.
CommonJS by Alex MacCaw
As CommonJS is simply a specification, we have a bunch of different implementations. There is also a number of Ruby-based solutions, but I’ll promote one of them—sprockets-commonjs. Yep, it’s based on Sprockets, so don’t forget to install it unless you are riding Ruby on Rails v3.1 or higher.
The rest of this article is the CommonJS quick-start guide. It may be helpful if you’re not satisfied with the official documentation.
Starting with CommonJS
Go to Gemfile and add the following command.
gem 'sprockets-commonjs'
If you are not using Ruby on Rails v3.1 or higher, you may also need this command.
gem 'sprockets-rails'
After that, you’ll be able to create CommonJS modules instead of ordinary JavaScript files. To do that, simply prefix a file extension with module
. For example, widget.js.coffee
should become widget.module.js.coffee
. Now, you get two new keywords.
require()
loads modules necessary for the current keyword.module.exports
specifies what should be returned if another module will require this keyword.
Let’s assume we have our widget.module.js.coffee
file inside of app/assets/javascripts/modules/
.
To use it in another module (for example, /modules/specific/window.module.js.coffee
),
we just need to use the following command.
We can also use a dot.
An absolute path can be used, as well.
The module
extension wraps your code with this command.
This callback is executed only if the module is required somewhere. That’s why you can no longer worry about the correct #= require
chain. A single #= require_tree ./modules
in application.js
would be enough.
require
is the only global variable exposed by sprockets-commonjs
. Except the module definition, it also allows for requiring modules from non-modules. In this case, don’t forget about the #= require
precedence.