Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
Coffeescript Source Maps in Rails
# config/initializers/source_maps.rb
if Rails.env.development?
require 'open3'
module CoffeeScript
class SourceMapError < StandardError; end;
class << self
def map_dir
return @map_dir if @map_dir
# Make the directory the maps are served from
@map_dir = Rails.root.join("public/source_maps")
def check_coffeescript_version
version = `coffee --version`
unless version.match(/(\d+)\.\d+\./)[1].to_i >= 2
raise "You must have coffeescript version 2.0.0-dev or higher to use source maps - see"
def compile script, options
script = if script.respond_to?(:read)
if options.key?(:no_wrap) and !options.key?(:bare)
options[:bare] = options[:no_wrap]
options[:bare] = false
compile_with_source_map script, options
def compile_with_source_map script, options
flags = %w(--js)
flags << "--bare" if options[:bare]
javascript, stderr, status = Open3.capture3("coffee #{flags.join(' ')}", stdin_data: script)
raise SourceMapError, stderr unless status.success?
source_map_comment = generate_source_map options[:pathname], script if options[:pathname]
return javascript << source_map_comment
rescue SourceMapError => e
message = e.message.lines.first.chomp.gsub('"', '\"')
relative_path_name = options[:pathname].to_s.gsub(Rails.root.to_s, '') if options[:pathname]
relative_path_name ||= '<unknown path>'
%Q{throw Error("Coffeescript compile error: #{relative_path_name}: #{message}")}
def generate_source_map pathname, script
basename = pathname.basename('.coffee')
coffee_file = map_dir.join("#{basename}.coffee")'w') {|f| f.puts script }
# This command actually generates the source map, and saves it to a file
source_map, status = nil
Dir.chdir Rails.root.join('public/source_maps').to_s do
source_map, stderr, status = Open3.capture3("coffee --source-map -i #{pathname.basename}")
raise SourceMapError, "Error while generating source map for file #{pathname}: #{stderr}" unless status.success?
# I couldn't figure out how to control the 'file' and 'sources' values in the output,
# so parse the map to JSON and rewrite these to ones that will work here
data = JSON.parse(source_map)
data['file'] = pathname.basename.to_s.gsub(/\.coffee/, '')
data['sources'] = [pathname.basename.to_s]
map_file = map_dir.join "#{basename}.map"'w') { |f| f.puts data.to_json } "Compiled source map #{map_file}"
return "\n//@ sourceMappingURL=/source_maps/#{map_file.basename}\n"
# Monkeypatch this method to include the scripts' pathname
require 'tilt/template'
module Tilt
class CoffeeScriptTemplate < Template
def evaluate(scope, locals, &block)
@output ||= CoffeeScript.compile(data, options.merge(pathname: scope.pathname))
Copy link

simonexmachina commented Oct 22, 2012

I found that I needed two newlines on line 85 because something in the pipeline was adding a semicolon to the end of the file, which meant that the browser wouldn't find the source map.

Also, I was disappointed to find that you can't actually edit the CoffeeScript in the DevTools :( Any idea whether this is/will be possible?

Copy link

almog commented Nov 2, 2012

@SimonWade Editing coffee code inside the DevTools debugging isn't possible.
Chrome doesn't know how to run coffeescript, but thanks to CoffeeScriptRedux compiler SMAP feature, it does have a 1 to 1 mapping between the compiled js code to the original coffee code.

Copy link

sdbondi commented Jan 19, 2013

Could someone please explain how to use this script, or how to get source maps to generate via the pipeline?
I have put source_maps.rb in config/initializers, but not sure what else is required.
I'm new to rails so bear with me ;)

EDIT: Through a bit of searching/looking at the link in the code: I was missing CoffeeScriptRedux - DOH - (a.k.a CoffeeScript 2) - just need to make sure that your dev webserver is using the correct 'coffee' binary (v2.0.0-x). Make sure you restart your server as any files in the /initializers directory won't be 'refreshed'. Also delete your /tmp to make sure your scripts are refreshed and the source map directive is added.

Copy link

sdbondi commented Jan 19, 2013

@SimonWade: I ran into the same problem but can't get rid of the semi-colon. Any ideas? I've tried adding newlines

Copy link

michaltaberski commented Feb 19, 2013

@sdbondi did you menage to solve problem with semi-colon? I`ve got the same.

Copy link

alexspeller commented Feb 24, 2013

Hi, not sure exactly what's adding semi-colons in the pipeline this is still working for me as-is on rails version 3.2.12.

Full instructions are available in my blog post about this. @michaltaberski @sdbondi please could you paste an example of actual output with the extra semicolon?

Copy link

turadg commented Mar 4, 2013

Anyone working on compiling in-process now that the coffee-script-source gem 1.6.1 and later support source maps?

Copy link

naan commented Mar 6, 2013

Copy link

obie commented Mar 26, 2013

If this isn't working for you because the generated source maps are missing their filename then try my workaround here:

Issue for underlying problem filed with coffescript project jashkenas/coffeescript#2806

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