Using Guard & Rake to compile Coffeescript in CakePHP

 Mar 21, 2013

I write most, if not all, of my client side code in Coffeescript now. While thats fine in Rails, which has a great asset management system, in other projects it can be a bit of a pain remembering to compile the files each time.

Now Coffeescript has its own watch flag which tells the compiler to watch a directory/file and compile it each time it changes, but sometimes the files are not all in one location and may be spread out through a project (for example each CakePHP plugin having its own CS files)

Enter Guard and Rake. Any Rubyist will be very familiar with the latter of these two gems, and most will have come across the former. I use them to run automated tasks on a project when certain events occur (like the saving of a file)

First off I’m going to assume you have Ruby installed, but if not check out RVM or rbenv, which are both great ways to get Ruby installed and manage different versions of the language.

Also, I’m assuming you have the Coffeescript compiler installed, which is beyond the scope of this post, but you can find out about it over at coffeescript.org

Next you’ll need three gems

$ gem install guard
$ gem install rake
$ gem install guard-rake

It’s very likely that rake will already be installed, but I’ve added it here for completeness.

Rake

You will need a Rakefile in your CakePHP app/ directory, mine contains a lot of tasks I use in my CakePHP workflow, but I’ve extracted the Coffeescript task below. I’ll touch on the other things I use Rake for in other posts

require 'fileutils'

task default: :coffee

desc "Compile the CoffeeScript files into JavaScript"
task :coffee do  
  coffee_path = 'coffee'
  sh "#{coffee_path} -o webroot/js/ -c Assets/js/coffee/"
  FileList.new('Plugin/*/').each do |plugin|
    if File.directory? "#{plugin}Assets/coffee"
      sh "#{coffee_path} -o #{plugin}webroot/js/ -c #{plugin}Assets/coffee/"
    end
  end
end

This task will allow you to run

$ rake coffee

in your app/ directory to compile all the Coffeescript files in the project.

The way my setup works, is that in my app directory I create an assets folder, which contains Coffeescript files in a coffee directory, something like this

-app
 |-Assets
    |-coffee
 |-Config
 |-Console
 |-Controller
<-snip->

(I also put my SASS files in here, but thats another post altogether)

The rake task looks for the Assets/coffee dir in the main app path and in all plugins in the Plugin path. It compiles the coffee script files to a Javascript file with the same name in the relative webroot/js directory.

This takes care of the compiling, and now we use Guard to automate it.

Guard

Much like rake, you will need a Guardfile in your app/ directory.

This contains a very simple block of code, which sets up Guard to watch all files in the app/ directory path with a .coffee extension, and if they change it runs the rake task we setup earlier

guard 'rake', :task => 'coffee' do
  watch(%r{.*?coffee$})
end

It basically tells Guard to run the rake command, passing the task coffee when the watched files change.
The watch command takes a regular expression for what type of files to watch.

You can check out more Guard functionality on the Github page

Running Guard

The last thing to do now is run the guard command in your app/ directory and it will run the rake task then start watching for changed to your coffee files.

Use CTRL-D to stop guard running

Final comments

The use of the Assets directory in my CakePHP workflow comes from an attempt to port an asset pipeline similar to the one in Rails over to CakePHP. I’m working through a post about how to do that and it will be up soon.

I prefer to use my asset pipeline method on new apps, but this form here works really well if you’re adding Coffeescript in to an existing app.

I also hope that it shows off some of the great tools in the Ruby eco-system that can help in any project regardless of the language its written in.

Guard-Coffeescript

It has been pointed out to me, that there is a Guard plugin especially for Coffeescript.

I wasn’t aware of it at the time I built this into my CakePHP workflow, but have recently installed it and will give it a try to see if it simplifies this process (I imagine it will)

Once I have enough experience with it I’ll either amend this post or write a new one about using the plugin with CakePHP