Using Cake for CoffeeScript compilation is fine for static sites, but for dynamic sites, we might as well integrate CoffeeScript compilation into the request/response cycle. Various integration solutions already exist for the popular backend languages and frameworks, such as Rails and Django.
The rest of this chapter explores how to actually structure and deploy CoffeeScript client-side applications. If youâre just using CoffeeScript on the server side, or your framework, such as Rails, already manages this, feel free to skip to Chapter 5.
For some reason, when developers build client-side JavaScript applications, tried and tested patterns and conventions often fly out the window, and the end result is a spaghetti mess of unmaintainable coupled JavaScript. I canât stress enough how important application architecture is; if youâre writing any JavaScript/CoffeeScript beyond simple form validation, you should implement a form of application structure, such as MVC.
The secret to building maintainable large applications is not to build large applications. In other words, build a series of modular de-coupled components. Keep application logic as generic as possible, abstracting it out as appropriate. Lastly, separate out your logic into views, models, and controllers (MVC). Implementing MVC is beyond the scope of this chapter; for that, I recommend you check out my book on JavaScript Web Applications and use a framework like Backbone or Spine. Rather than that, here weâre going to cover structuring applications using CommonJS modules.
So what exactly are CommonJS modules? Well, If youâve used NodeJS before, youâve used CommonJS modules, probably without realizing it. CommonJS modules were initially developed for writing server-side JavaScript libraries, in an attempt to deal with loading, namespacing, and scoping issues. They were a common format that would be compatible across all JavaScript implementations. The aim was that a library written for Rhino would work for Node. Eventually these ideas transitioned back to browsers, and now we have great libraries like RequireJS and Yabble to help us use modules on the client side.
Practically speaking, modules ensure that your code is run in a
local namespace (code encapsulation), that you can load other modules
with the require()
function, and that
you can expose module properties
via module.exports
. Letâs dive into
that in a bit more depth now.
You can load in other modules and libraries using require()
. Simply pass a module name and, if
itâs in the load path, itâll return an object representing that
module. For example:
User = require("models/user")
Synchronous require support is a contentious issue, but has mostly been resolved with the mainstream loader libraries and latest CommonJS proposals. It may be something youâll have to look into if you decided to take a separate route than the one Iâm advocating with Stitch below.
By default, modules donât expose any properties, so their
contents are completely invisible to require()
calls. If you want a particular
property to be accessible from your module, youâll need to set it on
module.exports
:
# random_module.js module.exports.myFineProperty = -> # Some shizzle
Now whenever this module is required, myFineProperty
will be exposed:
myFineProperty = require("random_module").myFineProperty
Formatting your code as CommonJS modules is all fine and dandy, but how do you actually get this working on the client in practice? Well, my method of choice is the rather unheard of Stitch library. Stitch is by Sam Stephenson, the mind behind Prototype.js among other things, and solves the module problem so elegantly it makes me want to dance for joy! Rather than try to dynamically resolve dependencies, Stitch simply bundles up all your JavaScript files into one, wrapping them in some CommonJS magic. Oh, and did I mention itâll compile your CoffeeScript, JS templates, LESS CSS, and Sass files too?
First things first, youâll need to install Node.js and npm if you havenât already. Weâll be using those throughout this chapter.
Now letâs create our application structure. If youâre using Spine, you can automate
this with Spine.App; otherwise,
itâs something youâll need to do manually. I usually have an app
folder for all the application specific
code, and a lib
folder for general
libraries. Then anything else, including static assets, goes in the
public
directory:
app app/controllers app/views app/models app/lib lib public public/index.html
Now to actually boot up the Stitch server. Letâs create a file
called index.coffee
and fill it with
the following script:
require("coffee-script") stitch = require("stitch") express = require("express") argv = process.argv.slice(2) package = stitch.createPackage( # Specify the paths you want Stitch to automatically bundle up paths: [ __dirname + "/app" ] # Specify your base libraries dependencies: [ # __dirname + '/lib/jquery.js' ] ) app = express.createServer() app.configure -> app.set "views", __dirname + "/views" app.use app.router app.use express.static(__dirname + "/public") app.get "/application.js", package.createServer() port = argv[0] or process.env.PORT or 9294 console.log "Starting server on port: #{port}" app.listen port
You can see some dependencies listed: coffee-script
, stitch
, and express
. We need to create a package.json
file, listing these dependencies
so npm can pick them up. Our ./package.json
file will look like
this:
{ "name": "app", "version": "0.0.1", "dependencies": { "coffee-script": "~1.1.2", "stitch": "~0.3.2", "express": "~2.5.0", "eco": "1.1.0-rc-1" } }
And letâs install those dependencies with npm:
npm install . npm install -g coffee-script
Rightio, weâre almost there. Now run:
coffee index.coffee
Youâll hopefully have a Stitch server up and running. Letâs go
ahead and test it out by putting an app.coffee
script in the app
folder. This will be the file thatâll
bootstrap our application:
module.exports = App = init: -> # Bootstrap the app
Now letâs create our main page index.html
which, if weâre building a single
page app, will be the only page the user actually navigates to. This is
a static asset, so itâs located under the public
directory:
<html> <head> <meta charset=utf-8> <title>Application</title> <!-- Require the main Stitch file --> <script src="/application.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript" charset="utf-8"> document.addEventListener("DOMContentLoaded", function(){ var App = require("app"); App.init(); }, false); </script> </head> <body> </body> </html>
When the page loads, our DOMContentLoaded
event callback is requiring the app.coffee
script (which is
automatically compiled), and invoking our init()
function. Thatâs all there is to it.
Weâve got CommonJS modules up and running, as well as a HTTP server and
CoffeeScript compiler. If, say, we wanted to include a module, itâs just
a case of calling require()
. Letâs
create a new class, User
, and
reference it from app.coffee
:
# app/models/user.coffee module.exports = class User constructor: (@name) -> # app/app.coffee User = require("models/user")
If youâre moving logic to the client side, then youâll definitely need some sort of templating library. JavaScript templating is very similar to templates on the server, such as Rubyâs ERB or Pythonâs text interpolation, except of course it runs client side. There are a whole host of templating libraries out there, so I encourage you to do some research and check them out. By default, Stitch comes with support for Eco templates baked right in.
JavaScript templates are very similar to server-side ones. You have template tags interoperated with HTML, and during rendering, those tags get evaluated and replaced. The great thing about Eco templates is theyâre actually written in CoffeeScript.
Hereâs an example:
<% if @projects.length: %> <% for project in @projects: %> <a href="<%= project.url %>"><%= project.name %></a> <p><%= project.description %></p> <% end %> <% else: %> No projects <% end %>
As you can see, the syntax is remarkably straightforward. Just use
<%
tags for evaluating
expressions, and <%=
tags for
printing them. A partial list of template tags is as follows:
<% expression %>
Evaluate a CoffeeScript expression without printing its return value.
<%= expression %>
Evaluate a CoffeeScript expression, escape its return value, and print it.
<%- expression %>
Evaluate a CoffeeScript expression and print its return value without escaping it.
You can use any CoffeeScript expression inside the templating
tags, but thereâs one thing to look out for. CoffeeScript is white space
sensitive, but your Eco templates arenât. Therefore, Eco template tags
that begin an indented CoffeeScript block must be suffixed with a colon.
To indicate the end of an indented block, use the special tag <% end
%>
. For example:
<% if @project.isOnHold(): %> On Hold <% end %>
You donât need to write the if
and end
tags on separate
lines:
<% if @project.isOnHold(): %> On Hold <% end %>
And you can use the single-line postfix form of if
as youâd expect:
<%= "On Hold" if @project.isOnHold() %>
Now that weâve got a handle on the syntax, letâs define an Eco
template in views/users/show.eco
:
<label>Name: <%= @name %></label>
Stitch will automatically compile our template and include it in
application.js
. Then, in our
applicationâs controllers, we can require the template, like it was a
module, and execute it passing any data required:
require("views/users/show")(new User("Brian"))
Our app.coffee
file should now
look like this, rendering the template and appending it to the page when
the document loads:
User = require("models/user") App = init: -> template = require("views/users/show") view = template(new User("Brian")) # Obviously this could be spruced up by jQuery element = document.createElement("div") element.innerHTML = view document.body.appendChild(element) module.exports = App
Open up the application and give it a whirl! Hopefully this tutorial has given you a good idea of how to structure client-side CoffeeScript applications. For your next steps, I recommend checking out a client-side framework like Backbone or Spine, Theyâll provide a basic MVC structure for you, freeing you up for the interesting stuff.
Heroku is an incredibly awesome web host that manages all the servers and scaling for you, letting you get on with the exciting stuff (building awesome JavaScript applications). Youâll need an account with Heroku for this tutorial to work, but the great news is that their basic plan is completely free. While traditionally a Ruby host, Heroku have recently released their Cedar stack, which includes Node support.
First, we need to make a Procfile
, which will inform Heroku about our
application:
echo "web: coffee index.coffee" > Procfile
Now, if you havenât already, youâll need to create a local git repository for your application:
git init git add . git commit -m "First commit"
And now to deploy the application, weâll use the heroku
gem (which youâll need to install if
you havenât already).
heroku create myAppName --stack cedar git push heroku master heroku open
Thatâs it! Seriously, thatâs all there is to it. Hosting Node applications has never been easier.
Stitch and Eco arenât the only libraries you can use for creating CoffeeScript and Node applications. There are a variety of alternatives.
For example, when it comes to templating, you can use Mustache, Jade, or write your HTML in pure CoffeeScript using CoffeeKup.
As for serving your application, Hem is a great choice, supporting both CommonJS and NPM modules and integrating seamlessly with the CoffeeScript MVC framework Spine. node-browsify is another similar project. Or if you want to go lower level with express integration, thereâs Trevor Burnhamâs connect-assets
You can find a full list of CoffeeScript web framework plug-ins on the projectâs wiki.
Get The Little Book on CoffeeScript now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.