Creating Deployment ready Javascript with Sprockets
If you’ve ever worked on a medium to large Ajax application, you know the headaches that Javascript can give you. On one hand you want to serve as few as possible Javascript files to users, but on the other you want to keep your sanity and work with lots of smaller files. This is where a build process comes in. It allows you to transform lots of files into one big file! You can even minify the big file for additional savings. There are many traditional build tools such as Ant, Make, and Phing. All of which are excellent tools for general building of assets. However, they often involve lots of XML, which I dislike having to use.
Sprockets
Thankfully, there is yet another build tool out there. Sprockets is a ruby library authored by Sam Stephenson of Prototype fame. Sprockets will pre-process and concatenate the Javascript files you tell it to. And just to make things even nicer, it supports a number of directives so you always have your dependancies. In addition Sprockets will strip out any inline comments, and allow you to use a YAML file to supply constants to your Javascript files.
Directives in Sprockets
There are two directives and they are both very simple
- //= require <name>
Will look on your build path for a file named name.js
and include it, if it has not already been included.
- // = require "name"
Will look in the current directory for name.js
and include it, if it has not already been included. I found that the include directives made Sprockets easy to use and afforded me the flexibility to break up my Javascript into more manageable pieces. For more information on sprockets directives check out the documentation
Using Sprockets
I installed Sprockets via ruby-gems and since Sprockets doesn’t handle minification I also installed the JSMin gem package. After reading the documentation, I was able to put together the following shell script which grabbed all my JS files, compacted and minified them into one file.
- #!/usr/bin/env ruby
- require 'rubygems'
- require 'Sprockets'
- require 'Jsmin'
- MINFILE = 'build.js'
- CONCATFILE = 'concat.js'
- secretary = Sprockets::Secretary.new(
- :asset_root => '.',
- :load_path => ['.', 'classes'],
- :source_files => ['*.js', 'classes/*.js'],
- :strip_comments => true
- )
- # generate the concatenation object
- concatenation = secretary.concatenation
- # write to disk
- gluedFiles = concatenation.to_s
- concatenation.save_to(CONCATFILE)
- # Run through JSMin
- File.open(MINFILE, 'w') { |file| file.write(JSMin.minify(gluedFiles)) }
So thats it, under 25 lines with comments and gratuitous comments. I can now easily generate concatenated and minified version of my common application javascript. I just run it from command line anytime I need to update the compacted assets.
Using Sprockets with CakePHP
Using this compacted JS file with CakePHP is a snap as well. I base it off of Configure::read('debug')
. So at debug 0 I want to use the compacted assets, and anything else I want all the small files so I can more easily debug and develop.
So what are you using to fight the tangle of Javascript that can accumulate when working on Javascript intensive applications?
Well written Mark.
I;ve only briefly touched on build systems for javascript. This is an excellent, practical overview of Sprockets. Its a system i had personally not used in the past. Thanks for sharing!
Graham.
Graham Weldon on 4/2/09
I’m using the Asset Packer Helper from Matt Curry myself, which works excellent. No need to build manually, but I guess there might be some performance tradeoffs.
Oscar on 4/2/09
One of the big advantages that Mark’s solution provides over my Asset Packer is the ability to deploy the files to a CDN.
At work I use a modified version of my Asset Packer to pre-build the files for CDN deployment. I wish this post had come out before then. It would have saved me a bunch of work.
Matt Curry on 4/6/09
Oscar: Matt’s Helper is another good solution to this problem, it also handles CSS which is nice. However, I think it requires your webroot to be writable by the server. So if you cannot make webroot world writable for some reason then a build script is needed.
mark story on 4/7/09