In a hindsight a year proved to be a ton of time on the client-side.
Most notably Grunt (which I only mentioned briefly) took off like a rocket, and in the same manner Yeoman - which I almost instantly considered a swiss army knife for doing my client-side only projects.
Yeoman though, which relies on Grunt, is going through some fundamental changes and looks like it is being re-arranged and re-planned for a while now.
For what it’s worth I do support the new Yeoman changes, but instead of waiting for it to crystalize I tought it is time to re-evaluate what’s out there today and see if Yeoman can be replaced altogather (the answer is ‘Yes’, keep reading :).
Ember.js and Sinatra
My current use case is fairly reasonable. Ember.js on the client side, and Sinatra providing a slim and fast API layer for the data.
Moving from Backbone to Ember as my client-side stack for a new project created a deep need for a solid asset pipeline with an effortless development experience, and looks like the most reasonable solutions right now are Grunt, rake-pipeline, and Sprockets.
Since I personally think dealing directly with Grunt build configuration is like dealing with an Ant build configuration in terms of flexibility (I remember a dark night just trying to do a certain file operation with Grunt) I hope you’ll forgive me for letting that one pass.
Things that I care about:
- Magical asset compilation: don’t care if it’s Coffeescript, sass, or less, detect and compile it for me. I care about Coffeescript and Sass.
- Dependency management: module dependency should be done properly.
- Smooth integration: with existing server-side stack.
- No friction: automate everything and live-reload.
- Production ready: bundling, minification, manifest, gzip, etc.
Note that I don’t include testing frameworks and runners integration here. I find that this area is so segmented (everyone has their own preference), that it may earn its own separate set of articles.
Here is the file structure we’ll use (a Ruby project):
Note I’m taking the Rails naming for the
assets folder (
stylesheets). It makes moving this thing to Rails
fairly easy if I’d ever want to completely separate the API from the UI.
How To Trigger a Build?
Assuming all of your assets are layed out and your pipeline configured, I came to a conclusion that there are two ways you can typically model your asset compilation for development
- File watcher and reactors - Guard does this well generically.
- On demand (per request) - Sprockets and asset-pipeline can work this way each using their own middleware for it.
Sprockets is the default asset pipeline in Rails for a long while now and is why I was sure it will work for me, and it did.
A couple notable things about Sprockets is its flexible asset
pipeline (it can handle a lot already out of the box) and the way it
does dependency with a
require directive, effectively injecting the body
of code instead of the
Sprockets with Guard
This way, everything will be Guard-driven. This means that changing code will trigger a series of processing steps that will drive everything that needs to be done in reaction to that change (asset compilation, browser reload, etc).
Let’s start with our
Gemfile. We’ll add
for better sass integration (we want compass),
coffee-script and finally
uglifier for minification. CSS
minification happens through the built-in Sprockets Sass
Now we’ll bootstrap our development environment and Guard itself with:
And create a
An important note to make here is that for
livereload we are watching
the generated files (which the
sprockets2 watcher generates), and not the source files. This is to avoid a race
condition where we modified a file, Sprockets is generating the file and
we pushed a live-reload event to the browser prematurely before it was finished.
my_project/app is a result of the Ruby application structure I use:
Namespace::App which I
consider a healthy project structure.
sprockets2 guard, where we specified a Sprockets Environment which
:sprockets => ..foo.. is one of the things that makes Sprockets
so flexible. This will make Guard understand what to compile
A bit more about Sprockets flexibility - since the
Environment we just
passed derives out of
which mixes in
(here) implementing the Rack-ish
Environment also becomes a natural Rack
we can use to compile assets on-demand (we’ll see that on the second part of
Though in our case,
guard-sprockets2 uses the Sprockets
not as a middleware but as a gateway
to compilation that it needs in order to build assets.
Ideally, we need to configure Sprockets in a central place, and offer it to whomever may be interested (we already saw how Guard made use of it).
We’ll do this within the configuration section of our Sinatra app.
uglifier Sprockets will try to
require things automatically the best way that it
can. What it means for us is that it’s enough to put
uglifier in our
The goal of
AssetHelpers here is to set up the paths for Sprockets to
be aware of and compute
on-demand path to assets when we’ll need those in our views (when we’ll do
<%= asset_path 'application.css' %>):
To start, just say
It will watch everything you do in
/assets and rebuild your assets
pushing them into
/public. You’ll miss another piece of you workflow
In Ruby, we need to do a couple of things in order to set up LiveReload:
- Detect changes
All that’s left is to inject the LiveReload script into every page. Easily done through a Rack middleware (
That’s it. If you managed to survive the long read, you should now have a good under-the-hood grasp of how toolsets like Yeoman works.
rackup now, you’ll discover that you have a fairly nifty Yeoman-like environment.
Using Sprockets as Middleware
When you use Sprockets as a middleware, it will recompile everything on every request you make. On a first glance, it sounds scary. On a second glance - you only do this in
development mode; you only compile and concatenate sources - no minifying or such intensive operations.
If you, like me, don’t think this such a waste given today’s CPUs - then you’ll want to drop the
guard-sprockets2 magic and use a simpler solution: Sprockets middleware.
As mentioned before, Sprockets’
Environment is already a middleware itself which is why it’s dead easy:
Since we’ve now inverted the pipeline model (we will pull the changes by refreshing the browser), Guard will need to watch different files.
And we can also remove
guard-sprockets2 from our
That’s it - now Guard is watching for file changes to support LiveReload, and Sprockets is compiling and serving assets on demand. To me this feels much cleaner, and is also very similar to how Rails does it (minus some minor differences).
Now that the setup is almost done, you can take a look at how Rails (this case 4.x) chose to configure and provide for Sprockets.
Everything we did now was to support a development workflow. If we moved out to using Sprockets as a middleware - how would we move a properly built, minified package to our production server?
Let’s create a rake task named
assets:precompile similar to the Rails
one in name, so that you can use the same infrastructure for this
application stack as well.
If you’re on Heroku though, you’ll have to run a manual
heroku rake for this one, but if you want to feel
like a boss you can fake it and make the Heroku
this is a Rails app, and run the
assets:precompile task automatically
(I’ll leave this to you, but I’ve linked a good hint of how to do that).
All that is left is to fake out this task with Sprockets, in your
Most of the heavy lifting was done by just our Sprockets configuration.
This completes our picture for Sprockets. We’ll now study an arguably more “elegant” asset pipeline called
Why another pipeline? well, in my opinion rake-pipeline is more hackable than Sprockets. This makes it very inviting to use in less typical projects, and even not necessarily web projects.
The developer API is pure awesome. Here is a quick example of defining what you want to do with your assets:
This is a real pipeline defined through a DSL; i.e. the output of the
coffee_script processor goes straight into the next step in the
pipeline with the help of a good input/output abstraction.
production? here is just my own addition (just checking an
environment variable). You can mix and match with your own to enrich the DSL.
Setting up rake-pipeline
rake-pipeline provides the foundation,
provides the extra pipeline steps, or filters, that we actually require
on a typical web app. You also get a CLI,
rakep which we’ll look at
As a convenience, here is our app file layout:
If Guard and dancing around configuration in our Sinatra app and Guardfile
were the main focus point of the Sprockets-based setup, in this case,
Assetfile will be it.
You can use this file verbatim as a starting point and tweak it to your own needs.
This time, there’s plenty more I don’t need in
production mode here.
This is due to the fact that I will not compute asset paths in the
views but use a predefined
/application.js - it
might be less flexible but is a very lean solution.
And to rig everything up in
development we configure this
(LiveReload configuration lifted off the Sprockets example):
For asset compilation, you’ll get a middleware that compiles on demand, like with the Sprockets middleware.
Everyhing that you outline in your
Assetfile will be used both in the
middleware and the CLI (
rakep), as well as
filters you can write on the spot. Here’s a custom filter example:
You might have noticed that once we moved off Sprockets, we have a
spot to fill for Sprockets’
require dependency management.
rake-pipeline This is done through a small and nifty
What you typically do is use
or Coffeescript code, and then run a
rake-pipeline filter which swaps
it out for the real thing.
And now, tuck this in your
Note that it is assumed that your client-side application code lives under
You’ll also need to make sure
minispade.js lives on your
folder untouched. It’s an extremely small solution for dependency
management and you can just put it in a
/static subfolder of your
With the above directive, we just told
rake-pipeline not to touch such
static content and just place it in the output destination. Just place
this directive at the bottom of your
Assetfile and it’ll be enough.
That’s it. As mentioned before this one feels a bit more hackable, a bit simpler.
rakep and Production
To build for
production all you have to do is use the
assets:precompile task and run the
rakep command which you get for
free with rake-pipeline.
Here’s an example
Rakefile for this:
Hopefully, this urged you to dip into the implementation details of these tools and libraries. As a side-effect you now have a kick-ass asset pipeline implementation that you can carry from project to project, and can freely hack on without subjecting yourself to a one-size-match-all solution.
Asset compilation pipelines, for me, proved to be a good study case of how to write code for libraries that can integrate well with other tools and libraries, expose a good DSL, and be very modular and flexible.