-
Notifications
You must be signed in to change notification settings - Fork 792
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Document how to generate and host source maps for production bug tracking #502
Comments
same issues for me now, I'm doing the exact same thing with you besides I want to upload to Sentry. But I also have no idea how to add the source map URL to the generated file. any updates? any suggestions would be grateful. |
There's not a way to do it at the moment without enabling all debug features. You can set I think it will map your sources correctly, but since those sources weren't compiled they won't be visible on the server. You'll still get the correct backtrace, and can use that to view your own sources locally though. |
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? |
@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.assets.debug = true
config.assets.resolve_with = %i[manifest] The second part you need to specify because by default, Rails (
Also in config.assets.js_compressor = :uglifier ( I guess you could set this in Then, in your //= 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.
If you're concerned about it still being available (though hard to find), you could manually delete the compiled 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.) |
@cllns Thanks for sharing that info! |
Thanks for the tips @cllns. Has anyone managed to get |
The commit that introduces The only place I can find it is in the sprockets-rails gem. def find_debug_asset(path)
if asset = find_asset(path, pipeline: :debug)
raise_unless_precompiled_asset asset.logical_path.sub('.debug', '')
asset
end
end If I'm understanding correctly, this means that Sprockets only adds I'd be happy to open a PR for this, but I'm not sure exactly what code needs to change. default_source_map.rb and source_map_utils.rb seem like candidates, but I'd appreciate guidance |
I was hoping I could just do this, but it results in infinite recursion: env.register_bundle_processor 'application/javascript',
Sprockets::AddSourceMapCommentToAssetProcessor And it doesn't appear that bundle processors have access to the compiled file paths. So perhaps there should be a concept of a bundle postprocessor? |
I couldn't find a good place to patch Sprockets, so I ended up writing an extension to https://gist.github.com/seanlinsley/ab0fb9fbc063e9812629be8cb6a92f2f The application I'm working on previously relied on having undigested assets for some JS libraries to use, which is a good thing b/c it turns out that the source maps that are generated link to undigested asset paths. Without the undigesting code, every file in the dev tools would be empty like this: |
@cllns mentioned this:
which appears to be true, though oddly breakpoints in a debugger don't stay in the right location like they do when the assets are statically compiled |
Hey @cllns were you able to send the |
@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) |
@cllns Were you able to find a way to generate the js source maps for rollbar? |
For those with similar issues, I was able to resolve it using the following steps
The above should generate source map when you run this command.
From Rollbar's documentation, the preferred method is via their API
sourcemap.rake
Note: The above rake task executes after the default Alternately, If you don't mind putting the sourcemap url in the minified JS --->
|
Any update on this? I'm trying to get source maps working in Now that source maps in production by default seems to be the official Rails position, can we expect some movement on this? |
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 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! |
I got as far as this (without modifying existing sprockets pipeline, based on comments above): lib/tasks/sourcemap.rakenamespace :assets do
def append_sourcemap
assets = JSON.parse(File.read(Dir[Rails.root.join('public/assets/.sprockets-manifest-*.json').to_s][0]))['assets']
assets.each do |name, digested|
ext = File.extname(name)
next unless ['.css', '.js'].include? ext
map_digested = assets["#{name}.map"]
next unless map_digested
file = Rails.root.join("public/assets/#{digested}")
mapping_string = "sourceMappingURL=#{map_digested}"
mapping_string = case ext
when '.css' then "/*# #{mapping_string} */"
when '.js' then "//# #{mapping_string}"
end
next if file.readlines[-1].include? mapping_string
file.open('a+') { |f| f << "\n#{mapping_string}" }
end
end
task precompile: :environment do
append_sourcemap
end
end This will append sourcemap to generated js files assuming they also have corresponding The problem is the As for esbuild output, here's my build.js#!/usr/bin/env node
import babel from '@babel/core'
import { createHash } from 'crypto'
import esbuild from 'esbuild'
import coffeeScriptPlugin from 'esbuild-coffeescript'
import fsPromises from 'fs/promises'
const outfileName = 'application.jsout'
const outfileEsbuild = `tmp/${outfileName}`
const outfileBabel = `app/assets/builds/${outfileName}`
const plugins = [
coffeeScriptPlugin({
bare: true,
inlineMap: true
}),
{
name: 'babel',
setup (build) {
build.onEnd(async () => {
const options = {
minified: true,
presets: [
['@babel/preset-env']
],
sourceMaps: true
}
const outEsbuild = await fsPromises.readFile(outfileEsbuild)
const result = await babel.transformAsync(outEsbuild, options)
result.map.sources = result.map.sources
// CoffeeScript sourcemap and Esbuild sourcemap combined generates duplicated source paths
.map((path) => path.replace(/\.\.\/app\/javascript(\/.+)?\/app\/javascript\//, '../app/javascript/'))
const resultMap = JSON.stringify(result.map)
const resultMapHash = createHash('sha256').update(resultMap).digest('hex')
return Promise.all([
// add hash so it matches sprocket output
fsPromises.writeFile(outfileBabel, `${result.code}\n//# sourceMappingURL=${outfileName}-${resultMapHash}.map`),
fsPromises.writeFile(`${outfileBabel}.map`, JSON.stringify(result.map))
])
})
}
},
{
name: 'analyze',
setup (build) {
build.onEnd(async (result) => {
if (options.analyze) {
const analyzeResult = await esbuild.analyzeMetafile(result.metafile)
console.log(analyzeResult)
}
})
}
},
]
const args = process.argv.slice(2)
const options = {
watch: args.includes('--watch'),
analyze: args.includes('--analyze')
}
esbuild.build({
bundle: true,
entryPoints: ['app/javascript/application.coffee'],
metafile: options.analyze,
nodePaths: ['app/javascript'],
outfile: outfileEsbuild,
plugins,
resolveExtensions: ['.coffee', '.js'],
sourcemap: 'inline',
watch: options.watch
}) The idea is to output the file to extension not recognized by sprockets so the files are not processed further. The map file in the comment point to digested filename as output by sprockets (with (should be slightly simpler if not using babel and coffeescript) |
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 #410 (comment).
I have successfully generated the source maps using the
link
directive in the manifest.js: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
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
The text was updated successfully, but these errors were encountered: