Happy debugging with JavaScript source maps

By: James Allardice

Tags:

  • javascript
  • sourcemaps

I’ve discussed previously the fact that we are gradually trying to improve the JavaScript behind the White Label Dating platform. The most recent step in this process has been to investigate the use of source maps when it comes to debugging our scripts.

What are source maps?

Obviously, our JavaScript library is served in the form of a single, minified file on production servers. During development, it’s a different story, with the various scripts that make up that library all included individually, in their original uncompressed form. This means it’s easy to identify any JavaScript issues during development, because most browser development tools will indicate at least a file name and line number when they encounter an error. But if we experience a live issue, that debugging becomes a whole lot harder. Have a look at this screenshot:

Unmapped JavaScript error

How are you meant to know where the error actually occurred? This is where source maps come in. A source map is effectively a technique to map a minified file back to its original, uncompressed state. For an excellent introduction to JavaScript source maps, I recommend that you read the HTML5 Rocks article on the subject. What we want to achieve is this:

Mapped JavaScript error

Notice how much easier it is to see the error. The clever thing is that the browser has actually downloaded the minified file, so the average user will be completely unaffected by the addition of a source map. The browser will only download the source map and unminified file when you ask it to (currently, that’s done by opening the developer tools of Chrome or Safari and enabling source maps).

Generating our source map

The first step was to integrate the generation of our source map into our build process. We use Grunt to produce production builds of our JavaScript library, and we use the Google Closure Compiler for minification. Fortuantely, the Closure Compiler can also generate source maps. There is already an excellent Grunt plugin that adds Google Closure support, so we use that too. All that remains is to add a section to the Grunt script that uses Closure to produce a source map:

 
grunt.initConfig({
    "closure-compiler": {
        sourcemap: {
            js: "build/library.js",
            jsOutputFile: "build/library.min.js",
            options: {
                create_source_map: "build/library.min.js.map",
                source_map_format: "V3"             
            }        
        }     
    } 
});

That works well so now any time we run our build script, we get a source map file in the output directory. Unfortunately, the Closure Compiler is not yet capable of adding the reference to the source map to the minified script which means we add it ourselves. The current source maps specification gives the following format. It’s just a normal JavaScript comment so browsers that don’t support source maps will completely ignore it:

//@ sourceMappingURL=library.min.js.map 

Adding this comment manually after each build would be annoying. Luckily, it’s very easy to extend Grunt so we’ve written a simple plugin to handle it for us. By including that plugin in our build script, all we have to do is add another small section to the Grunt config:

grunt.initConfig({
    "closure-compiler": {
        // Closure compiler configuration
    },
    "append-sourcemapping": {
        main: {
            files: {
                "build/library.min.js": "library.min.js.map"
            }
        }
    }
});

Fighting with Internet Explorer

It was never going to be that simple. Turns out that there’s a problem using source maps in all versions of Internet Explorer under certain circumstances. If you’ve ever seen or used conditional JavaScript compilation in IE, you may have recognised the format of that source map include comment earlier.

If a library with a source mapping comment is included in a page after conditional compilation has been turned on (it’s turned on with a comment containing the string @cc_on @), you’re going to end up with JavaScript errors. Internet Explorer will attempt to parse your source map comment as part of the program, and will almost certainly fail because the source map URL (library.min.js.map in the example above) will not be a valid identifier.

For more details of the issue, see this jQuery bug report. That ticket also details a very simple workaround. By simply wrapping the source mapping comment in a multiline comment, Internet Explorer will not attempt to parse it, even when conditional compilation is active. All we had to do was make a little change to our Grunt plugin to get the comment output looking like this:

/*
//@ sourceMappingURL=library.min.js.map
*/

And that’s all there is to it. We now have working source maps in WebKit browsers, and Firefox support is supposed to be in the works. Over the next few months, we should see more and more chatter about this emerging technique so get a head start and implement source maps in your JavaScript libraries as soon as possible.


About the Author

James Allardice

James Allardice is a Senior JavaScript Developer at Venntro. He is passionate about clean, maintainable JavaScript and is regularly on the lookout for ways to improve the JavaScript development process. He's currently interested in JSHint, Grunt, AngularJS and ECMAScript6.