Dr Nic

Using CoffeeScript in Rails and even on Heroku

I’m pretty excited about CoffeeScript as a clean-syntax replacement for pure JavaScript.

What is CoffeeScript?

Imagine all the syntactical delights of Ruby and Haml for your JavaScript. You write in a nice language, but get normal JavaScript at runtime. All whilst having full access to 3rd-party JavaScript libraries (jQuery, PrototypeJS), debugging support (it becomes pure, readable JavaScript), existing support from test suites (it’s normal JavaScript) and growing support from various text editors (TextMate, Vim, Emacs).

What simple delights?

No trailing semi-colons. No { some_code() } function/closure brackets. String interpolation. Multi-line strings. Explicit class syntax. Array slicing. An existential ? operator.

Scroll down the home page for awesome example after example.

These aren’t library extensions. This is clean, purposeful syntax.

You can play with the joyful syntax of CoffeeScript on the website. After reading the basic examples on the CoffeeScript home page, press “TRY COFFEESCRIPT” in the header menu.

As you play with the syntax, the equivalent JavaScript is printed on the right hand side (see image above).

How nice is that syntax? Very.

Installing CoffeeScript

  1. Install NodeJS
  2. Install CoffeeScript

For NodeJS (get latest release URL; using 0.1.31 as 0.1.32 doesn’t unpack for me):

cd /usr/local/src
wget http://nodejs.org/dist/node-v0.1.31.tar.gz
tar xfv node-v0.1.31.tar.gz
cd node-v0.1.31
./configure
make
sudo make install

For CoffeeScript (get latest release URL):

cd /usr/local/src
wget http://github.com/jashkenas/coffee-script/tarball/0.5.5
tar xfv jashkenas-coffee-script-bcf7b3f.tar.gz
cd jashkenas-coffee-script-bcf7b3f
sudo bin/cake install

Now test that everything is in place:

$ coffee --version
CoffeeScript version 0.5.5
$ coffee -e "sys: require 'sys'; sys.puts 'hello world\n'"
hello world

Phew!

Note, in the command-line/on the server, you are using the NodeJS JavaScript environment. It supports the CommonJS API for loading modules (normal JavaScript: var sys = require('sys')).

Um, but how do I use it in my web app?

Your application source code will have *.coffee files containing your sexy, short CoffeeScript. But at runtime, the browser needs the generated JavaScript.

I’ve been using the Jonas Nicklas’ bistro_car gem:

gem install bistro_car
mkdir -p app/scripts

In your Rails config/environment.rb file, add:

config.gem 'bistro_car'

And in your layouts, such as app/views/layouts/application.html.erb add to the <head> or the bottom:

<%= coffee_script_bundle %>

Now you’re good to go. Add your CoffeeScript files in app/scripts/*.coffee and they will be automatically available as JavaScript.

WARNING: Check your version of CoffeeScript

Check that this hasn’t happened:

$ coffee --version
CoffeeScript version 0.3.2
$ which coffee
/usr/bin/coffee

Arrgh, we should be using /usr/local/bin/coffee. bistro_car currently installs the old rubygem-based version of coffee-script; and you might be unlucky to have your $PATH find the wrong one first.

Either delete it (sudo rm /usr/bin/coffee and restart your shell) or make sure /usr/local/bin is earlier in your $PATH than /usr/bin, where RubyGems installed the old, unnecessary version of coffee command.

Let’s drink the CoffeeScript

Create a file app/scripts/application.coffee with contents:

powers: [1,2,3,4].map (i) -> i * i
alert powers

Load up a view in a browser and see [1,4,9,16]. You win! Throw in some jQuery/PrototypeJS/whatever. Beautiful.

View the source of the page, navigate to public/javascripts/bundle/default.js and you’ll see the generated source:

(function(){
  var powers;
  powers = [1, 2, 3, 4].map(function(i) {
    return i * i;
  });
  alert(powers);
})();

The problem: Heroku doesn’t have CoffeeScript installed

Heroku is a great place to host apps. Though it doesn’t have CoffeeScript installed so it cannot dynamically convert the *.coffee files into JavaScript.

If you want to use Heroku I guess we need to perform the conversion locally and deploy it.

But. In development and integration testing I want bistro_car’s dynamically generated default.js. In production, I need a cached version.

In application.html.haml I use (I can’t keep pretending I use erb):

- if Rails.env.production?
  = javascript_include_tag "coffeescripts"
- else
  = coffee_script_bundle

Now we’re just left with the hassle of automatically generating public/javascripts/coffeescripts.js.

First, a rake task. Second, a git pre-commit hook.

Create lib/tasks/bistro_car.rake:

desc "Generate the cached bundle/default.js file from app/scripts/*.coffee files"
task :bistro_car => :environment do
  path = "public/javascripts/coffeescripts.js"
  puts "Building *.coffee -> #{path}"
  File.open(path, "w") { |file| file << BistroCar::Bundle.new('default').to_javascript }
end

file "public/javascripts/coffeescripts.js" => Dir[File.join(Rails.root, 'app/scripts/*.coffee')] do |t|
  Rake::Task["bistro_car"].invoke
end

Now you can create coffeescripts.js and add it to the repo with:

rake public/javascripts/coffeescripts.js
git add public/javascripts/coffeescripts.js
git commit -m "Initial bundled coffeescripts file"

Now create .git/hooks/pre-commit:

#!/bin/sh

exec rake public/javascripts/coffeescripts.js

And make it executable (and git commit will invoke it automatically):

chmod +x .git/hooks/pre-commit

Phew.

Now, whenever you change a *.coffee script and you are about to commit it, the cached-production-only coffeescripts.js is automatically updated and included in the same commit.

Seems like a clean hack.

Summary

Why not make a library to do this? Well I’m hoping there is a better, cleaner way. Perhaps bistro_car can include a rails generator to package these bits and pieces itself, if my approach happens to be the best way.

Nonetheless, let history record that CoffeeScript is very cool though in the world of Heroku living with it is non-trivial at the moment.

Related posts:

  1. Instant new Rails applications with the App Scrolls When I start a new project I want to start...
  2. Validate and Save your Ruby in TextMate – with secret Rubinus superpowers In some TextMate bundles, if you save a file it...
  3. Showcase of CoffeeScript – 2.5 mins for your next Dev Group meeting If you are giving an “Introduction to CoffeeScript” talk...
  4. Dead simple JavaScript Unit Testing in Rails Formats: Video/Screencast (410 Mb, torrent) | Video only (vimeo)...
  5. First look at rails 3.0.pre This article is out of date in some aspects....

17 Responses to “Using CoffeeScript in Rails and even on Heroku”

  1. Will Bridges says:

    This looks pretty exciting. I have to say I hate writing javascript… it’s like taking me back to my PERL days almost.

    The only problem with it I have is the same problem I have with haml. It’s another layer of abstraction that people on my team have to learn and/or as we grow contractors working on our projects will have to understand if we adopt it. Many, many people know javascript (and hate it). However, that being said, it’s not a reason to not adopt it if you can. It looks like it makes things much easier.

  2. Thanks for the great writeup, Dr. Nic.

    If you like, using CoffeeScript with any web framework needn’t be complicated. The “coffee” command comes with a “–watch” option, which will rebuild your JavaScript files every time the source CoffeeScript is saved. So, running something like this:

    coffee –wc -o public/javascripts app/coffee/**/*.coffee

    Would be a fine way to keep your JS up to date as you develop. From there you can include it normally with the asset packager of your choice. No plugins or Heroku hacks required.

  3. Dr Nic says:

    @Jeremy – oh awesome. I’ll get that wired up; and perhaps also extend the TextMate bundle to auto-generate the JavaScript files when saving *.coffee files.

    Then I’ll update the article. That is, cut it in half!

  4. Dr Nic says:

    @will – because coffeescript does compile directly to JavaScript before use, and it’s not hidden, I think it can be safely used in an environment where there is pre-existing JavaScript.

    If you decide to give up on coffeescript, you just throw the *.coffee files away and you keep the clean, generated JavaScript files.

    Alternately, you can piece-meal convert your JavaScript files to CoffeeScript as you get to them.

    It should definitely help ppl engage with JavaScript. Especially when JavaScript is now more prevalent on the server side and it should be possible to “try a chunk of JavaScript” without having to set up a dummy HTML page, etc.

  5. Guoliang Cao says:

    This is wonderful. I’ve been using haml + sass, now I can use coffeescripts for my Javascript need. I’m familiar with Javascript but it’ll be interesting to see where coffeescripts can lead me to.

    Thank you for the nice writeup!

  6. Dr Nic says:

    @Jeremy – for coffee 0.5.5 what worked for me was:

    coffee app/scripts/*.coffee -wc -o public/javascripts

    It seems the options must come last.

  7. There is also rack-coffee if you want to serve them up via Rack. Eager to try this out and see if it plays nice with Heroku.

    http://github.com/mattly/rack-coffee

  8. Dr Nic says:

    @wynn – I think rack-coffee still requires `coffee` command to exist on the server (which it doesn’t on heroku)?

  9. [...] I ran into a slight problem when following Dr Nic’s setup tutorial today. CoffeeScript worked, bistro_car worked within the console, but it didn’t work when [...]

  10. Jeff says:

    This is wonderful. I’ve been using haml + sass, now I can use coffeescripts for my Javascript need. I’m familiar with Javascript but it’ll be interesting to see where coffeescripts can lead me to.

    Thank you for the nice writeup!

  11. Tony says:

    @Jeremy – for coffee 0.5.5 what worked for me was:

    coffee app/scripts/*.coffee -wc -o public/javascripts

    It seems the options must come last.

  12. Daniel says:

    Thanks for the great writeup, Dr. Nic.

    If you like, using CoffeeScript with any web framework needn’t be complicated. The “coffee” command comes with a “–watch” option, which will rebuild your JavaScript files every time the source CoffeeScript is saved. So, running something like this:

    coffee –wc -o public/javascripts app/coffee/**/*.coffee

    Would be a fine way to keep your JS up to date as you develop. From there you can include it normally with the asset packager of your choice. No plugins or Heroku hacks required.

  13. Don says:

    @will – because coffeescript does compile directly to JavaScript before use, and it’s not hidden, I think it can be safely used in an environment where there is pre-existing JavaScript.

    If you decide to give up on coffeescript, you just throw the *.coffee files away and you keep the clean, generated JavaScript files.

    Alternately, you can piece-meal convert your JavaScript files to CoffeeScript as you get to them.

    It should definitely help ppl engage with JavaScript. Especially when JavaScript is now more prevalent on the server side and it should be possible to “try a chunk of JavaScript” without having to set up a dummy HTML page, etc.

  14. One more update for folks who find this blog post via Google… As of CoffeeScript 0.6.2, using the `coffee` command to compile will now preserve directory structure.

    coffee -wc -o public/javascripts app/coffee

    Will now walk the `app/coffee` directory, and compile CoffeeScripts that it finds into the corresponding location in `public/javascripts`.

  15. moda says:

    Thanks for the great writeup, Dr. Nic.

  16. Sam says:

    Is there a way to go from Javascript to CoffeeScript so I can convert my current JavaScript code and standardize on CoffeeScript?

    Awesome write up!

  17. [...] okazja. Gem bistro_car ułatwia organizację skryptów w aplikacji Railsowej, a Dr Nic napisał świetny tutorial wprowadzający do tego [...]