Skip to content

Instantly share code, notes, and snippets.

@lachie
Created August 18, 2011 11:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save lachie/1153919 to your computer and use it in GitHub Desktop.
Save lachie/1153919 to your computer and use it in GitHub Desktop.
rails 3.1 asset pipeline + stitch/CommonJS
// in app/assets/javascripts/application.js
//= require jquery
//= require jquery_ujs
//= require ./stitch_header
//= require_tree .
I really like node.js & its commonjs module system.
I like the idea of stitch & stitch-rb http://alexmaccaw.co.uk/posts/2011/06/30/rails_js_packaging.html.
But I'm also pragmatic... I also "like" the rails asset pipeline & its bandwaggonny weight.
So I combined the two approaches.
It'd be good to combine the two into a gem, but here's how it'd be shaped.
# in app/assets/javascripts/something.coffee
class exports.Something
// in app/assets/javascripts/stitch_header.js
(function(/*! Stitch !*/) {
if (!this.require) {
var modules = {},
cache = {},
require = function(name, root) {
var module = cache[name], path = expand(root, name), fn;
if (module) {
return module;
} else if (fn = modules[path] || modules[path = expand(path, './index')]) {
module = {id: name, exports: {}};
try {
cache[name] = module.exports;
fn(module.exports, function(name) {
return require(name, dirname(path));
}, module);
return cache[name] = module.exports;
} catch (err) {
delete cache[name];
throw err;
}
} else {
throw 'module "' + name + '" not found';
}
},
expand = function(root, name) {
var results = [], parts, part;
if (/^\.\.?(\/|$)/.test(name)) {
parts = [root, name].join('/').split('/');
} else {
parts = name.split('/');
}
for (var i = 0, length = parts.length; i < length; i++) {
part = parts[i];
if (part == '..') {
results.pop();
} else if (part != '.' && part != '') {
results.push(part);
}
}
return results.join('/');
},
dirname = function(path) {
return path.split('/').slice(0, -1).join('/');
};
this.require = function(name) {
return require(name, '');
}
this.require.define = function(bundle) {
for (var key in bundle)
modules[key] = bundle[key];
};
}
}).call(this)
# in config/initializers/stitchy.rb
require 'stitchy_coffee_script_template'
YourApp::Application.config.after_initialize do
YourApp::Application.assets.register_engine '.coffee', StitchyCoffeeScriptTemplate
end
# in lib/stitchy_coffee_script_template.rb
require 'tilt'
class StitchyCoffeeScriptTemplate < Tilt::Template
self.default_mime_type = 'application/javascript'
def self.engine_initialized?
defined? ::CoffeeScript
end
def initialize_engine
require_template_library 'coffee_script'
end
def prepare
options[:bare] = true
end
def evaluate(scope, locals, &block)
@output ||= "\nrequire.define({'#{ module_name(scope) }': function(exports, require, module) {\n" + CoffeeScript.compile(data, options) + "\n}});\n"
end
private
# this might need to be customisable to generate the desired module names
# this implementation lops off the first segment of the path
def module_name(scope)
scope.logical_path.split('/')[1..-1].join('/')
end
end
# in app/assets/javascripts/your_file.coffee
{Something} = require('something')
class exports.YourApp extends Something
@doitian
Copy link

doitian commented Feb 22, 2012

This code cannot work in Rails 3.1.0, I built a same gem for this: https://github.com/doitian/stitch_rails

YourApp::Application.config.after_initialize do
  YourApp::Application.assets.register_engine '.coffee', StitchyCoffeeScriptTemplate
end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment