Geoff
Geoff

Reputation: 9580

What is a good way to separate concerns with CoffeeScript and Ruby on Rail's asset pipeline?

TLDR:

What can you do to combine multiple CoffeeScript files into one JS file, in RoR, all under the same anonymous function block?

Long version:

I have a few CS files that will be loaded for part of a RoR web app. I'm wondering: what is a good way to separate concerns with CoffeeScripts and Ruby on Rail 3.1's asset pipeline?

Let's use the following as example code:

main.js.coffee

window.MyApp = {} # to escape the CoffeeScript anonymous function block
# (I like the anonymous function block because it protects my other

MY_GLOBAL_SETTING = "world!"
$.click "#my_button" myApp.sayHello
# (I could use something like goog.bind here instead of using myApp. Any suggestions? Fat arrow?)

hello.js.coffee

MyApp.sayHello = sayHello () ->
  doComplicatedStuff()
  alert("Hello #{ MY_GLOBAL_SETTING }")

complicated.js.coffee

doComplicatedStuff = () ->
  # some really complicated algorithm, for example
  true

I have my assets directory structured like the following:

assets/
  application.js
  application/
    # javascript that gets used with the main application
  secondary_page.js
  secondary_page/
    complicated.js.coffee
    hello.js.coffee
    main.js.coffee

secondary.js

//= require secondary_page/main.js.coffee
//= require secondary_page/complicated.js.coffee
//= require secondary_page/hello.js.coffee

I used to compile the files together with CoffeeScript as part of the build process, but now I want to use the asset pipeline instead. I'm drinking the RoR 3.1 kool-aid! Haha, seriously though, the asset pipeline looks awesome.

The problem I'm experiencing is that secondary.js looks like the following:

(function() {
  // main.js
).call(this);
(function() {
  // complicated.js
).call(this);
(function() {
  // hello.js
).call(this);

This prevents local variables from being shared amongst the entire code. MY_GLOBAL_SETTING and doComplicatedStuff aren't available to sayHello.

So... what should I do? I can't think of a good way without introducing my own custom compilation step again.

Upvotes: 0

Views: 568

Answers (2)

Trevor Burnham
Trevor Burnham

Reputation: 77416

This is a common question for Rails developers starting to use CoffeeScript. See, for example:

Solutions abound. The simplest is to preface variable declarations that you want to be visible outside of a particular file with @, since the this will point to window in the outermost context of each file, and x points to window.x when no local x is defined.

Upvotes: 2

Steve Ross
Steve Ross

Reputation: 4144

Probably the best way to do this is to leave them in their own anonymous scopes but export the individual functions you need access to from other modules. From Trevor Burnham's Coffeescript book, he recommends you do this (which works in node and browsers):

root = global ? window
root.exportableFunction = exportableFunction
root.MY_GLOBAL_SETTING = some: 'Setting'

Upvotes: 0

Related Questions