How do I use Node and Express with coffeescript and requirejs?

coffeescript, express, node.js, requirejs

Solution

I've created a package to help solve this problem; it's called connect-assets-jspaths.

From the readme:

Installation

`npm install connect-assets-jspaths`

- Note, there is a dependency on CoffeeScript.

Server Side Usage

assets = require "connect-assets"
jsPaths = require "connect-assets-jspaths"

# Snip ...

app.use assets()
# Exports the global function exportPaths() and jsUrl(); see below in View Helpers.
jsPaths assets

# Optionally, pass a log function to see progress
# jsPaths assets, console.log

Watch changes and re-compile

Now you can pass some additional callbacks in and it will monitor your connect assets directories for changes.

fileChangedCallback = (err, filePath) ->
    console.log "File Changed: #{filePath}"

jsPaths assets, console.log, fileChangedCallback, (err, watcher) ->
    console.log "Watcher initialized"

NOTE You'll probably want to disable this for production mode.

View Usage

This module exports two global functions `exportPaths()` and `jsUrl()`.

// Using this in your view
!= exportPaths("jsPaths")

// Turns into this when rendered in production
<script type="text/javascript">
    var jsPaths = { "main", "/builtAssets/js/main.13819282742.js" /* snip all the other file paths */ };
</script>


// Using this in your view
- var mainJsPath = jsUrl("/js/main.js")
script(type="text/javascript", data-main="#{mainJsPath}", src="//cdnjs.cloudflare.com/ajax/libs/require.js/2.0.2/require.min.js")    

// Turns into this when rendered in production
<script type="text/javascript" data-main="/builtAssets/js/main.13819282742.js" src="//cdnjs.cloudflare.com/ajax/libs/require.js/2.0.2/require.min.js"></script>

Dynamic RequireJS Paths

Now that we have a variable with our requireJS friendly paths in it, we can set those paths in the RequireJS config

# Example main.coffee file in /assets/js folder

requirePaths =
  paths:
    jquery: "//cdnjs.cloudflare.com/ajax/libs/jquery/1.7.2/jquery.min"
    underscore: "//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.3.3/underscore-min"
    backbone: "//cdnjs.cloudflare.com/ajax/libs/backbone.js/0.9.2/backbone-min"
    text: "/js/lib/text"
    handlebars: "/js/lib/handlebars"

if jsPaths
  for own key, value of jsPaths
    # Fix up the lib references
    key = key.slice 4 if key.slice(0, 4) == "lib/"
    requirePaths.paths[key] = value 

require.config
  paths: requirePaths.paths

  shim:
    jquery:
      exports: "$"
    underscore:
      exports: "_"
    backbone:
      deps: ["underscore", "jquery"]
      exports: "Backbone"

require ['app'], (App) ->
    new App().initialize()

Problem

Here's what I want. - A node application using the express webserver - Using coffeescript on the server and more importantly the client - Using require.js on the client (and eventually on the server) The recommended way I've been able to find of hooking up coffeescript for the client is to use connect-assets. This seems to require using jade helpers to actually compile coffeescript eg. ``` !=js('monalisa.js') ``` seems to compile monalisa.coffee and generate the correct `<script>` tag. Now I want to use require.js and here I stumble. How do I ensure that connect-assets compiles everything correctly without using the jade helpers? Here's my fairly simple app.js: ``` require('coffee-script'); var express = require('express') , http = require('http') , path = require('path') , connectAssets = require('connect-assets'); var publicDir = path.join(__dirname, 'public'); var app = express(); app.configure(function(){ app.set('port', process.env.PORT || 3000); app.set('views', __dirname + '/views'); app.set('view engine', 'jade'); app.use(express.favicon()); app.use(express.logger('dev')); app.use(express.bodyParser()); app.use( connectAssets() ); app.use('/public', express.static(publicDir)); app.use(express.logger()); app.use(express.methodOverride()); app.use(app.router); }); app.configure('development', function(){ app.use(express.errorHandler({ dumpExceptions: true, showStack: true })); }); app.get('/', require('./routes').index); app.get('/monalisa', require('./routes/monalisa').monalisa); http.createServer(app).listen(app.get('port'), function(){ console.log("Express server listening on port " + app.get('port')); }); ```

Original source