Source maps

See your errors right within your unminified source code

By default, if your error is in an external script file, Errorception shows you the error right within your script itself. However, if your code is minfied and everything is on line 1, it can be quite daunting to debug such code. If you publish your source map files, Errorception will show you your error right within your original unminified code!

Screenshot showing source maps in Errorception
Screenshot of a typical error with source maps applied.
Notice the indented code with line-breaks, from the original source code, with the exact error highlighted.

Source maps: A quick overview

A source map file, usually generated by your minifier, is a file that contains a mapping of line and column numbers between your original and minified code. It helps you answer the question Given a line and column in your minified source, what file, line and column number does it map to in your original unminified source code? It's easy to see how this information can be immensely useful for debugging tools. Read the HTML5 Rocks article for details.

Source maps are supported natively by Chrome and Firefox and you can use them in their respective developer tools when debugging your code. Errorception uses the same source maps to highlight exactly where your errors are in your original source code.

What source maps are not: Source maps don't actually contain your original source code itself, only the mapping between your minified and unminified code. For any tool to use source maps effectively, it must also have access to your original source code.

Generating source maps

Since source maps store the mapping between the original and minified source, your minifier is in the best position to generate the source map. You'll have to look at your minifier's documentation to find out how to generate source maps.

Generating source maps with UglifyJS2

Source maps using UglifyJS2

You can create source maps with UglifyJS2 by using the --source-map flag.

uglifyjs script.js --source-map script-min.js.map

There are several source maps related options in UglifyJS2, so be sure to give the docs a look.

Generating source maps using Google Closure Compiler

Source maps using Closure Compiler

You can create source maps with Google Closure Compiler by using the --create_source_map flag.

java -jar compiler.jar \ 
--js script.js \
--create_source_map ./script-min.js.map \
--source_map_format=V3 \
--js_output_file script-min.js

The --source_map_format is required and should always be set to V3. Closure compiler will now create a script-min.js.map file for you when minifying your scripts. Easy peasy!

Upload your source map and your original source code

To make your source maps available, you will need to upload them to somewhere, so that it can be found easily. The easiest place to upload it is your own web server. This way, you can build your source maps using your build scripts, and deploy them with your deployment script. You will also have to upload your original source code along with your source map files.

A common mistake is that your original script files aren't reachable by Errorception. This happens if your source code isn't uploaded, or if the source map file points to the wrong path for your source files. You will need to ensure that the sources key in your source map file resolves to a valid file on your web server. The .map file is a large JSON file, so you should be able to read it easily in a text editor.

The crawler

Whenever an error occurs on your site, Errorception's crawler downloads a copy of your minified script. Your minified script is then parsed to extract the source map's file path. Source maps are discovered by either looking for the //# sourceMappingURL=scripts.js.map comment in your minified code, which would have been inserted by your minifier, or by looking for the X-SourceMap HTTP header.

Once your source map is found, Errorception decides which of your original source files are needed (depends on the error and its stack frames), and attempts to download them from your web server too.

This means that there are two possible points of failure. First when trying to download your source map file, and the second when attempting to download your original source files. You'll have to ensure that the paths resolve correctly for both these cases.

Private source maps

The downside of the approach above is that your source map file and your original source code files are all public. If you don't care about this, you don't need to worry about private source maps. If however having your source code out in the public is not something you are comfortable with, you can make small tweaks to ensure that your code is less public.

You can make your source map files private using one of two ways:

Whitelisting Errorception's IP address

The simplest and most comprehensive way of making your source maps private is to restrict access to only Errorception's crawler's IP address. The configuration for this is web-server-specific, so I haven't documented them here. You can read nginx's docs, or apache's docs, if those are your web servers. Errorception's crawler runs from 173.255.210.131.

Restricting access by IP addresses gives you the additional benefit of having source-maps work in your browser's dev-tools within your office's IP-range, if you also allow access to your office's IPs. This lets you use source-maps when you are trying to debug an issue on production, while your code remains inaccessible outside your network.

You'll have to make your built code publicly accessible, and your original source code only accessible to Errorception's (and your network's) IP. Since the source map file itself doesn't contain your code, you don't need to make that private, but you could if you want to. ;)

Using a secret folder

If for any reason you can't whitelist Errorception's IP, you could make your source-code mostly private by using the secret folder technique mentioned below. This doesn't require making tweaks to your web server, but it requires some changes to your build process.

Firstly, strip the source map URL from your script file. You could do this either by asking your minifier to do so, or by writing a simple script to remove the source map comment pragma once your build is complete. Since this is the starting point for everything to do with source maps, your source map and source files become undiscoverable.

However, this makes your source map file undiscoverable to Errorception as well. What you can then do is tell Errorception where to look for your source map file, and Errorception will take over from there. This way, only Errorception knows where your files are located, and your files are otherwise undiscoverable. This makes your code much more hard to find.

You should specify a secret folder, which you can do in your Settings > Source Maps. Errorception then uses the script's path and the secret folder to determine where to look for your source map file. For example, if your minified script is at http://www.example.com/javascripts/script.js, and you've specified your secret folder to be secret, Errorception looks for your source map at http://www.example.com/javascripts/secret/script.js.map. Or, if your minified script is at /a/b/c/script.js, Errorception looks for the source map at /a/b/c/secret/script.js.map.

Once the source map file has been discovered by Errorception, your original source files are discovered by the paths specified in your source map file itself, in the sources attribute. These could be relative to the source map file itself, or indeed be an absolute path to anywhere you like.

But that's still public!

Yes, this form of security is really only security by obscurity. However, it's worth noting that (unless you've turned on directory listing), it's impossible to find your secret folder, because it isn't linked to from anywhere.

That said, you could argue that someone could still chance upon your original source files if they guess your secret folder name correctly. If you want to ensure absolute security, you'll have to use the technique above of restricting access by IP addresses.

All of this might sound overwhelming, but it really isn't. I'd love to help you along if you face any trouble at all. Feel free to get in touch.