Deploy Coffeescript Node App to Heroku

So you’ve got a cool node app written in Coffeescript and you want to deploy it to Heroku?

Seems like it should be easy these days, right?

Not so much. Well, let’s be honest, we’re in the future, you don’t have to manually manage servers, etc. (Thank you Heroku!) but deploying a Coffeescript app is still no small task as there are a bunch of gotchas. Hopefully this will help.

Structure of Coffeescript node app

The following instructions assume you have the following rough structure to your application:

/
|-- package.json
|-- Procfile
+-- src
     |-- app.coffee

The general idea here is that your app source .coffee files will live in the /src directory and when they’re pushed to Heroku, they’ll magically be compiled into the /target directory as js files.

This has the nice fringe benefit as it means this compilation from coffee to js happens just once with each push.

So after pushing your app will look like this on the Heroku servers:

/
|-- package.json
|-- Procfile
+-- src
|    |-- app.coffee
+-- target
     |-- app.js

Where target/app.js is the compiled version of src/app.coffee

Buildpack

Heroku has things called Buildpacks which are a bundle of scripts to be run when code is pushed to Heroku. They have official Buildpacks for Node, Rails, and the other most common frameworks, but none for Coffeescript as of the time of this writing.

So some research and I found @aergonaut had a great buildpack for coffeescript.

To add this buildpack to a new node app you can use the following command to create the app:

$ heroku create --buildpack https://github.com/aergonaut/heroku-buildpack-coffeescript.git

You can also add it to an existing app:

$ heroku config:set BUILDPACK_URL=https://github.com/aergonaut/heroku-buildpack-coffeescript.git

Procfile

You will have to make sure your Procfile is properly configured for this as well.

It should contain the following:

web: node target/app.js

Note how it’s hitting target/app.js which will be the compiled copy of your app.

Even though you may have an empty target directory on your local machine, it will get populated with the compiled app code on push to Heroku.

Development

Without compilation

During development, you can run your code locally without compilation if you’d like:

$ coffee src/app.coffee

If you want to do this with Foreman it’s easy to create a Procfile.dev and tell Foreman to use it:

$ web: coffee src/app.coffee

Then to run it:

$ foreman start -f Procfile.dev

Manual compilation

You can also compile the code manually, just as the Buildpack will on a push to Heroku:

$ coffee --compile --bare --output target src

Automated compilation

My favorite approach is to have all of this happen automagically, with some linting as well using Grunt Grunt to watch for changes and compile everything in the /src directory into the /target directory.

First, if you haven’t already, install the Grunt dependencies:

$ npm install grunt grunt-cli grunt-contrib-coffee grunt-coffeelint --save-dev

Then create or edit your Gruntfile:

module.exports = (grunt) ->
  grunt.initConfig
    coffee:
      compile:
        files: [
          expand: true
          cwd: 'src'
          src: '**/*.coffee'
          dest: 'target'
          ext: '.js'
        ]
    coffeelint:
      app: 'src/**/*.coffee'
    watch:
      files: ['Gruntfile.coffee', 'src/**/*.coffee']
      tasks: ['coffeelint', 'coffee']
 
  grunt.loadNpmTasks 'grunt-coffeelint'
  grunt.loadNpmTasks 'grunt-contrib-coffee'
  grunt.loadNpmTasks 'grunt-contrib-watch'
 
  grunt.registerTask 'default', ['watch']

Then run it:

$ grunt

Not only will that watch the directory for changes and compile it whenever a file is written, but it will also lint the files! Then the app can be run:

$ node target/app.js

Or, since this is just the way it will look when pushed to Heroku, you can use Foreman with the normal Procfile to run it:

$ foreman start

Note how under the coffee task I have

files: [
  expand: true
  cwd: 'src'
  src: '**/*.coffee'
  dest: 'target'
  ext: '.js'
]

This basically instructs Grunt to recurse through every subdirectory of src/, find each .coffee file, and compile it to create a .js doppelganger under target/.

This means src/app.coffee becomes target/app.js and src/config/db.coffee becomes target/config/db.js and so on.

If you’re going to do this local auto-compilation, I suggest adding target/ to your .gitignore file. No need for that to get committed to your repo!

Push it!

Of course this is all well and good, but until you actually push it to Heroku it isn’t doing you much good!

$ git push heroku master

You should see something like:

Counting objects: 11, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (6/6), done.
Writing objects: 100% (9/9), 883 bytes, done.
Total 9 (delta 3), reused 0 (delta 0)
 
-----> Fetching custom git buildpack... done
-----> Coffeescript app detected
-----> Resolving engine versions
       Using Node.js version: 0.8.25
       Using npm version: 1.1.65
-----> Fetching Node.js binaries
-----> Vendoring node into slug
-----> Installing dependencies with npm
 
       ...
       
       Dependencies installed
-----> Compiling coffee source
       Source compiled to target
-----> Building runtime environment
-----> Discovering process types
       Procfile declares types -> web

Note: I replaced all the npm dependency installation as … above for brevity

Note how it says Coffeescript app detected

This is due to the Buildpack referenced above. If it finds .coffee files in the src directory, it recognizes it as a Coffeescript app.

After it has installed the dependencies, including the coffee-script module, it will compile the coffee source from src/ into target/ and start your app.

Published 10 Aug 2013

Scaling and leading engineering and data teams to solve the world's problems
Victor Quinn on Twitter