sprockets: Document how to generate and host source maps for production bug tracking

Goal: Give bug trackers like bugsnag access to sprockets generated source maps.

Hi all, I’m trying to have my bug tracker use source maps in production and staging. This references the discussion happening in https://github.com/rails/sprockets/issues/410#issuecomment-270474542.

I have successfully generated the source maps using the link directive in the manifest.js:

//= link source.js
//= link source.js.map

I am ok including sourceMapURL= in the final minified js file (despite it not being best practice). However, I’ve been unable to get this to happen for production builds, only debug. Maybe this is straightforward and I’m missing an option. Is it a simple configuration in an initializer? There is already this configuration for debug:

https://github.com/rails/sprockets/blob/master/lib/sprockets.rb#L106-L108

  register_pipeline :debug do
    [SourceMapCommentProcessor]
  end

I would prefer to just host the source map file and have my bug tracker pick it up from a url.

That being said, @vincentwoo mentioned that he POSTs it up to sentry.io. How do you know how to pair the source file with the map file if they have different digests? Do you have your own processor?

Thanks for any help.

System configuration

  • Sprockets version 4 beta 5
  • Ruby version 2.4.1 on rails 5.0.6

About this issue

  • Original URL
  • State: open
  • Created 7 years ago
  • Reactions: 15
  • Comments: 17 (1 by maintainers)

Most upvoted comments

@emiellohr I imagine you don’t need help anymore, but I just worked on this today. Hoping this will help others trying to do this too.

To config/environments/production.rb, add:

config.assets.debug = true
config.assets.resolve_with = %i[manifest]

The second part you need to specify because by default, Rails (sprockets?) only tries :manifest if debug = false, which it’s clearly not in our case. The other value that can be in that array is environment but that doesn’t work for me, even as a backup, and I’m using :manifest anyway. If you don’t do this, Rails will generate non-digested pathnames, which won’t work, since sprockets still digests them when they’re compiled.

debug = true for production feels weird, but it’s not so bad. Even in development, it still concatenates the file (this is different than the normal behavior, where debug = true typically means that the files are unconcatenated and unminified) no matter what. (I’m guessing this is manifest.js behavior.)

Also in config/environments/development.rb, config.assets.debug is probably already true (if it’s not, make it true). surprisingly here, you need to add a JS compressor in order to get the source maps to work in development:

config.assets.js_compressor = :uglifier

( I guess you could set this in config/initializers/assets.rb or elsewhere, if you wanted, but that means the :test environment would compress JS, which will probably not handle sourcemaps as elegantly as the browser).

Then, in your app/assets/config/manifest.js, add a corresponding .map file for each .js file you have. For example:

//= link application.js                                                                                        
//= link application.js.map

Now, when you deploy, the map will be compiled too. Letting people see your JS is a minor security problem, but, crucially, there’s no link to it in your JS files, so it’s very hard to find.

The reason development knows where your source map is, is that the following line is added to the bottom of your minified JS. Thankfully, this does not happen in production.

//# sourceMappingURL=application.js-d54377f4bfe13c83f772d0a7c353127a0d7388afe67fcca1344b5cdac0370c1c.map

If you’re concerned about it still being available (though hard to find), you could manually delete the compiled .map file from your compiled assets as a part of your build process.

The above notes might be wrong, it’s just my experience from working on this today. Hopefully it helps someone 😃

(I still need to work on modifying my build process to send the source map to my error logging service, Rollbar. That should be relatively simple, since they’re being generated already.)

Sorry to bump this but we’re also in the same situation, we want source maps in production (like DHH). After waiting years for sprockets to support this we were very happy to see that sprockets 4 officially added support (thanks 🙇), but then when trying to upgrade we noticed there’s actually no way to use it in production… (without brittle hacks mentioned above).

I totally understand that there may be a majority still considering this a bad practice and thus keeping it disabled by default in production seem ok. But there could at least be an option to enable it for people who want to, no?

Thanks!

For those with similar issues, I was able to resolve it using the following steps

  1. upgrade sprockets to v4 beta 7 . gem 'sprockets', '~> 4.0.0.beta7'

  2. create a manifest file

 //= link application.js.map
 //= link_directory ../javascripts .js
 //= link_directory ../stylesheets .css

The above should generate source map when you run this command. bundle exec rake assets:precompile RAILS_ENV=production

To send source map to an error reporting service(in this case Rollbar)

From Rollbar’s documentation, the preferred method is via their API

  1. create a rake task that sends the generated source map via the API - this should be done before deployment

sourcemap.rake

namespace :assets do 
  LOCAL_SOURCEMAP_PATH = `search/get the generated sourcemap path`

  def sourcemap_to_rollbar
    puts HTTP.post("https://api.rollbar.com/api/1/sourcemap",
      form: {
        access_token: ROLLBAR_TOKEN,
        version: VERSION_IDENTIFIER,
        minified_url: MINIFIED_URL_PATH,
        source_map: HTTP::FormData::File.new(LOCAL_SOURCEMAP_PATH)
      }
    )
  end

task :precompile do
    if Rails.env.production?
      sourcemap_to_rollbar
    end
  end

Here I’m using https://github.com/httprb/http for making request from Ruby

Note: The above rake task executes after the default rake assets:precompile runs, it doesn’t replace the default rails task

Alternately, If you don’t mind putting the sourcemap url in the minified JS —>

def sourcemap_to_rollbar
  source_map = Dir.glob("#{'public/assets'}/**/*application-*.map") //get source map path
  minfied_file = Dir.glob("#{'public/assets'}/**/*application-*.js")  //get minifies js

  minfied_file.open(file, "a+"){|f| f << "\n //# sourceMappingURL=" + source_map } //place url path at the bottom of the minified JS
end

Any update on this?

I’m trying to get source maps working in production as well. I was able to get them generated by following @cllns’s instructions above. But I’m also not able to get it to add a sourceMappingURL comment.

Now that source maps in production by default seems to be the official Rails position, can we expect some movement on this?

@framky007 I was able to send the source maps to Rollbar, but not in the way Rollbar expected (so, they didn’t work in Rollbar’s interface)

I don’t get it. Can someone please explain? I’ve upgraded my Rails project to Sprockets 4, just to get source maps in production. Instead I got sourcemaps in development? How does this work? Do I need an additional initializer or config setting?

@cllns Thanks for sharing that info!