Simplifying Large CoffeeScript Project Builds With Cake
command for production compilation and deployment… you’re ready for a slice of Cake!
Now you’re ready to enjoy some Cake with your Coffee!
Note: npm just turned 1.0 and the
-g flag tells npm to install CoffeeScript globally, so it is available across your projects and system. You can read more about it on the node blog post.
A Taste of Cake
In addition to being a logical progression of the classic
rake build system names,
cake borrows some familiar concepts from those systems. A
Cakefile defines tasks that
cake can perform, written in essentially a tiny CoffeeScript DSL.
That means that all of CoffeeScript’s lovely syntax is available for use. Additionally, since
cake depends on
node, you have all of the power of
node’s API and libraries at your finger tips. That’s kind of a big deal.
Organizing a CoffeeScript Project
Since I like test-driven development, I have some general project organization patterns that I like to follow. Here’s a simple example:
Cakefile /production /coffee-script intro.coffee MyGreatClass.coffee outro.coffee /js /test /coffee-script MyGreatClassSpec.coffee /js
Note the implied ordering of the production CoffeeScript files. Logically, the contents of
intro.coffee should precede
CoffeeScript has a
-j [FILE] command line switch that lets you easily concatenate file names in order into a single,
FILE.coffee. However, if we’re reading a directory asynchronously in node, even if our
*.coffee files are explicitly named to fall into proper order, there is no guarantee that they will be returned in that order.
If you notice tasks or file reads occurring in a seemingly random order, this asynchronous behavior is most likely the culprit. Of course, there are methods to enforce specific ordering of events that I’ll discuss below.
In order to guarantee the proper ordering of our application’s component files, we need to establish an array of those file names, iterate over them and concatenate each file’s contents. To give you an idea of how I currently like to set up my Cakefile, here’s what I’d call the preamble, the portion before I define any tasks.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
Like any node application, I require a few modules first. Then I simply assign a few values for project-specific directory layout,
coffee options for test and production code, and finally the aforementioned array of CoffeeScript files I’d like concatenated in a particular order. Now let’s take a look at a task that concatenates and builds our production CoffeeScript.
Cakefile Build Task
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
I won’t step through this code as it’s pretty easy to follow. I shamelessly lifted a few patterns from Jeremy’s Wiki and they have served my projects well. What you should take away from this
task is that to guarantee small component concatenation order in a large CoffeeScript project, you’ll need to specify that ordering in your Cakefile. It is not sufficient to hand node a directory which will
dir your project files in the correct order and expect them to be arranged and built that way!
For ease of development, the last task we’ll take a look at is a simple
cake watch task that will look for changes to our individual CoffeeScript files and invoke our
cake build task when it sees them. This is the task that makes developing your project in CoffeeScript extra pleasant.
Cakefile Watch Task
1 2 3 4 5 6 7 8
Again, this is pretty simple CoffeeScript to follow. We’re making use of node’s watchFile
fs method to look for changes to all
*.coffee files in our production source directory. When modification times differ, we are invoking the
build task outlined above. With this task, you can fire up your command line and execute:
in your project’s root (where your
Cakefile should be!) and go on your way happily hacking CoffeeScript all day long.
A Piece of…
cake, even with the simplest Cakefile tasks, can help you organize and streamline your CoffeeScript workflow. I have tried to illustrate how
cake can help bring order to your growing CoffeeScript project in a sensible and lightweight manner. A half hour spent writing a
Cakefile and tweaking your project structure can mean a big return on time and effort as your project matures.
There isn’t a whole lot of documentation available detailing writing even simple Cakefile tasks at the moment and I hope I’ve helped to fill that gap a bit with this post. If you’d like to explore more in-depth examples I’d suggest cruising github for successful CoffeeScript projects and studying their Cakefiles. There’s also the brief annotated
cake source that can help shed some light onto this build system.
With the power of node’s API and the clarity of CoffeeScript’s syntax, you’ve got another great excuse to love
Sample Skeleton CoffeeScript & Cake Project
I’ve updated my earlier skeleton project for beginning JasmineBDD and CoffeeScript with some of the
cake tasks and ideas described in this post. Feel free to take a look, clone/fork/etc., try it out and enjoy! My project is available on github.
P.S. - Other Cakefile Task Ideas
- Integrate task success/failure messages with a local notification system (i.e. Growl). My example project illustrates this.
watchtask for a mini-CIT loop while you work.