-
Notifications
You must be signed in to change notification settings - Fork 2
[HowTo] Compiling and Setting Up Build Tools
This page is work-in-progress. Please check back later
cake
is coffee
's little sister (or so I picture things). If you installed CoffeeScript using npm
then you should already have access to it. If you used cake install
you have in fact had first-hand experience with the tool.
If you have symlinked bin/coffee
to a new location on your $PATH
then you should also symlink bin/cake
:
$ ln -s /home/stan/public/coffee-script/bin/cake /usr/local/bin/cake
The above assumes /usr/local/bin
is in your $PATH
.
Running cake
outside of CoffeeScript's main directory is much likely to end up throwing an exception and printing out a stack trace. If you look closely, you can see why things don't work just yet:
Error: Cakefile not found in /home/stan/
So, how about we create one:
$ cd ~
$ vim Cakefile
Leave the file empty for the time being. Run cake
again:
$ cd ~
$ cake
This should return immediately without printing anything to stdout
.
Yes, we are doing the infamous Hello World example but with a spin -- inside a Cakefile
. If you have worked with rake
or make
then you should already have an idea of how things work. You define a task and use cake [task name]
to execute it. Let's get started:
$ cd ~
$ vim Cakefile
Define the task as say:hello
:
task 'say:hello', 'Description of task', ->
puts 'Hello World!'
Save and exit back to the shell. Next, let's run our newly created task:
$ cake say:hello
Hello World!
Running cake
again but without any arguments you get a list of all available tasks and their description:
$ cake
cake say:hello # Description of task
Try running cake
inside CoffeeScript's main directory, observe the output.
Using coffee
on the command-line allows you to compile a directory recursively and output all resulting JavaScript files to another directory. Let's see how we can do that:
$ cd ~/public/coffee-script
$ coffee --compile --output lib/ src/
The above command will compile all src/*.coffee
files to lib/*.js
. While working on your application you may have different directories from the ones used above, but for the sake of this example we will assume src
and lib
.
Let's move on and create our compile task inside a new Cakefile
under our project's main directory:
$ cd ~/projects/my-coffee-script-project
$ vim Cakefile
Paste the following code inside:
{exec} = require 'child_process'
task 'build', 'Build project from src/*.coffee to lib/*.js', ->
exec 'coffee --compile --output lib/ src/', (err, stdout, stderr) ->
throw err if err
print stdout + stderr
The build
task launches the command we used earlier and waits for it to complete. Upon successful compilation it prints any output (usually none so add your own) or throws an exception should coffee
have exited with a status code greater than 0 (indicating a compilation failure).
If you are working on a browser application you may want to concatenate all your files into one and serve that instead. The caveat here is you should concatenate all your source *.coffee
files before you compile them. If you simply concatenate the resulting *.js
files, you end up with a closure for each file and duplication of utility functions (CoffeeScript produces these when extending classes, binding functions, etc.)
When we are dealing with multiple files, ordering usually matters unfortunately. We could iterate the src/
directory looking for all *.coffee
files using node.js, but the API is asynchronous and the results we get back are not ordered in any way. Instead, we should define a list of files we want to process to build our application file:
fs = require 'fs'
{exec} = require 'child_process'
appFiles = [
'content/scripts/statusbar'
'content/scripts/command/quickMacro'
'content/scripts/command/selectionTools/general'
]
task 'build', 'Build single application file from source files', ->
available = 0
appContents = new Array appFiles.length
for file, index in appFiles
fs.readFile "src/#{file}.coffee", 'utf8', (err, fileContents) ->
throw err if err
appContents[index] = fileContents
process() if ++available is appFiles.length
process = ->
fs.writeFile 'lib/app.coffee', appContents.join('\n\n'), 'utf8', (err) ->
throw err if err
exec 'coffee --compile lib/app.coffee', (err, stdout, stderr) ->
throw err if err
print stdout + stderr
fs.unlink 'lib/app.coffee', (err) ->
throw err if err
puts 'Done.'
We start off by defining our appFiles
which we want to concatenate and then process. The build
task starts by reading all of the files asynchronously and calls process()
when all files have been read. process()
in turn writes a temporary file under lib/
and compiles that to lib/app.js
. Study the source and modify it as you see fit for your own needs.