we recently updated our asset bundling and naming scheme to improve our site speed and cache-ability. we achieved our goals, but the more we mangle and bundle our code, the more we introduce ways in which bugs show up only in production.
making our development environment better match our production environment will go a long way in helping not only debugging these issues but preventing them. it’s a long path and step one is sourcemaps.
sourcemaps took a bit of wrangling in our environment, but i was able to get everything working after about a week of head banging. yesterday, i got this message:
i just used sourceMaps to debug an issue in staging and it was magical
this makes all the blood sweat and tears worth it. thank you for the note, ankit!
Four Take Aways
here are 4 take aways worth sharing from this project, in the hopes that it will help you get it right too:
1. The Internet Is Full Of Halp
patrick muellr wrote a nice set of sourceMap best practices on his blog that i thought was worth following. we even named our sourceMap files with the .json extension, because after all, it is a json file.
mozilla’s nodejs sourceMap library. use it. i tried a couple of other libraries to help dealing with concatenating sourceMap files and i kept running into problems. digging deeper, i found all these libraries just used mozilla’s library under the hood. their interface is intuitive and their documentation is super clear.
i found it easier to do all the manipulation of our sourceMaps using their library directly instead of the other helper libraries i found on github.
well done mozilla. as usual.
2. sourcesContent Rocks
sourcesContent is an array field in sourcemaps where you can embed the original source into the map itself. this means you no longer have to manage three URL mappings and three files (original source, compiled source and sourceMap).
less is moar.
if you are optimizing your site speed, you are likely concatenating many files together.
managing a one to many file relationship gets tricky, but with sourceMaps and it’s sourcesContent field, you can represent one giant bundled file by just one sourcemap.
3. Integrating SourceMaps Into Your Build
most compilers / transpilers like uglify, closure, react-tools, coffeescript and babel all have sourceMap generation built into them.
however, if you want to preserve these sourceMaps and/or you have a chain of compilers/transpilers working together (like we do at Coursera), you are going to have to roll up your sleeves and add some glue.
with so many files getting processed by our builds, it’s worth the effort to keep things simple.
one way to do this is to use relative URLs and to keep the sourceMaps at the same path as the original source itself. it just gets really messy if you try to get fancy. (trust me, i tried)
many build tools don’t always just concat files, but they modify the source files directly.
for example, r.js normalizes each file directly. since we generate the sourceMaps manually (rather than using what r.js produces), all our sourceMaps ended up pointing to the wrong lines.
we solved this by building a normalizer task into our build and updating the sourcesContent with these changes (thanks to james burke for pointing us in the right direction)
4. The sourceRoot Magic Trick
i didn’t end up learning a lot about the reasons or use of sourceRoot, but i did find one use for it.
we named our sourceRoot ‘sourceMaps’ and now all the sourceMaps appear under the virtual folder ‘sourceMaps’. this allows the developer to quickly find their sourceMaps but still be explicit that the files are merely abstractions of what files are being used by the app.
What’s Next …
we still have more work to do in making our development and production environments be as similar as possible.
one path forward is to have all developers build apps with optimizations and bundling turned on. for this approach to work, we will need to speed up our build process and make our optimized builds incremental.
but that will be for another blog (and hopefully another developer) …