Build Management for Javascript, Coffescript and Friends

Update, 16-feb: I've added Brewer.js to the review.

tl;dr

Find a tool that can compile coffeescript, take javascripts and vendor javascript libs, join them preserving order, and minify them into one file good for release. If that tool can do CSS/stylus/sass all the better. I pick sprockets eventually and show how you can tailor it to your needs.
<!-- more -->

Its also been quite a journey and I've not to make it tiresome and include all of the details. My best offer if you have questions is just follow me and tweet me up.

Custom made concoctions

This is the quickest way you can have at setting up a build for your code, and sometimes it is just enough. However, you'll need to either copy-paste this each time, or extract it into a boilerplate/tool.

To do this, you can use plain cat and minify command line libraries with a Makefile, use closure compiler with ruby, or use uglifyjs with node Cakefiles.

Dedicated tooling

First some words about CommonJS and its module system. From the spec:

This specification addresses how modules should be written in order to be interoperable among a class of module systems that can be both client and server side, secure or insecure, implemented today or supported by future systems with syntax extensions. These modules are offered privacy of their top scope, facility for importing singleton objects from other modules, and exporting their own API. By implication, this specification defines the minimum features that a module system must provide in order to support interoperable modules.

stitch

With it, you can use CommonJS in your browser. Find it here: sstephenson/stitch. If you want to be using CommonJS out of Node's environment (a good thing), it presents a problem - the browser doesn't really understand CommonJS.

This is why we need to have an HTTP server serving on-the-fly content from stitch, which chews up the CommonJS export directive into a browser-compatible structure, or a CLI tool that watches for changes and rebuilds you files on demand. Stitch doesn't come with those, but it does come with a couple great examples of how to easily make them on your own on the README.

hem

Quite a new tool, looks like hem was built to provide great build experience for Spine.JS. It too supports CommonJS (via stitch), which is my preferred way to do dependencies with javascript.

I was able to customize it to my own needs (I'm not doing Spine.JS at the moment) and make it work pretty quickly; however, I couldn't help but feel that I was abusing it, just because the terminology in the config file is web app specific (I have no /public folder like a web app would have, nor is what I'm building considered a web app).

sprockets

The familiar pipeline from Rails. I'm already using it in my Rails projects so I have nothing really stopping me except a couple of things.

For one, it doesn't use CommonJS (but then again I use that on Rails so..), and secondly, with the lack of Rails pipeline glue I have to manually rebuild the package every time I make an update via the sprockets commandline.

While this is not too bad, it becomes a problem when I don't even have (or want) a server-side in my project.

PS: There is also a sprockets inspired Node based tool called interleave.

Brewer.js

This library touched my radar a night after I've published this article. Looks like it was created 2-3 days before that too.

It looks like a great solution, I may have picked it if that was the first solution that occurred to me. It works quite similar to sprockets and interleave, and injects dependencies (not CommonJS).

Lumbar

A great build management tool from walmartlabs. Feels like it packs a ton of punch, but may be too overkill for my needs.

It doesn't come OOB with coffeescript support (it does with stylus support). Regarding CommonJS, it is not using stitch but it does provide their own version for it. If my project was intensively complex in terms of dependencies and build targeting, I'd use that, and I'd take the time to build the appropriate CoffeeScript plugin.

brunch

http://brunch.io. Since I've used it before, at first, this was my go-to solution. It offers almost zero developer friction, nice guidelines and best practices, and great preprocessor support for any language that I needed.

However, currently minification is utterly broken, and looks like the tool itself undergoes some kind of a rewrite. If you're willing to make minification an external step, this may be an excellent choice.

Note: I kinda stayed away from tools such as Jammit, Squishit (for you .Net guys), and Juicer. They do what I need only to a degree.

What did i choose?

Basically we can narrow it down to one question.

Do we want to use CommonJS?

If so, then stitch, hem and Lumbar are in that space (brunch can use require.js).

If not, then sprockets or a custom build file will do the job just fine. Take note that to use sprockets easily (read: without coding too much), you can use the sprockets command line tool (which, given its history was taken out and pulled back in), and some kind of watch detection (guard-sprockets might be nice for you).

Eventually I settled on sprockets.

Here's how you could set it up, too. Needless to say you need Ruby for this.

With an example directory layout such as this:

/
 - /app
    - index.js
    - your.coffee
    - your.js
 - /vendor
    /js
      - jquery.js
      - backbone.js
      - underscore.js
 - /build
    - output.lives.here.js
 - Gemfile
 - Guardfile

You should set up a Gemfile like so ``` ruby source :gemcutter

gem 'sprockets'
gem 'guard-sprockets'
gem 'coffee-script'
gem 'uglifier'
Follow with `bundle install` and your environment is basically ready. We'll want to do a `guard init`, and `guard init sprockets`.  
Make sure to preprend with `bundle exec` when needed.




Lets edit our `Guardfile` to make sure we build the right bundle. In this case my code lives in `/app` and my vendored things in `/vendor`. I called my main javascript file (through which i `require` others) `index.js`

``` ruby
    guard 'sprockets', :destination => "build", :asset_paths => ['app', 'vendor'] do
      watch (%r{^app/.*}){ |m| "app/index.js" }
    end

We will watch everything (via the app/.* regex) and let sprockets build our root file (app/index.js). Again, the root file includes our sprockets require directives (see sprockets)

You're Up!

If you go bundle exec guard start, you should have a compiled script ready every time you make changes to files in /app in your /build folder.

One last thing

The code that was generated is not minified. Well, turnes out guard-sprockets isn't supporting that, so I've added support.

For this, you will have to modify your Gemfile to take my own fork of guard-sprockets (for more detail, see https://github.com/sstephenson/sprockets/issues/279):

    gem 'guard-sprockets', :git => "git://github.com/jondot/guard-sprockets.git"

Now we finish up by updating our Guardfile, so that it knows we want minified content:

    guard 'sprockets', :destination => "build", :asset_paths => ['app', 'vendor'], minify => true do
      watch (%r{^app/.*}){ |m| "app/index.js" }
    end

Finito

Run bundle exec guard start again, make a modification, and you'll see your code compiled and minified!.