Source map support for web page debugging has been a thing now for a while.
If you don't know what a sourcemap is, Ryan Seddon's article
"Introduction to JavaScript Source Maps", provides
a technical introduction. The "proposal" for source map seems to be
here.
In a nutshell, sourcemap allow you to ship minized .js files (and maybe .css
files), which point back to the original source, so that when you debug your
code in a debugger like Chrome Dev Tools, you'll see the original source.
It's awesome.
Even better, we're starting to see folks ship source maps with their minized
resources. For example, looking at the
minized angular 1.2.0-rc.2 js file
you can see the sourcemap annotation near the end:
/*
//@ sourceMappingURL=angular.min.js.map
*/
The contents of that .map file looks like this (I've truncated bits of it):
{
"version":3,
"file":"angular.min.js",
"lineCount":183,
"mappings":"A;;;;;aAKC,SAAQ,CAACA,CAAD,...",
"sources":["angular.js","MINERR_ASSET"],
"names":["window","document","undefined",...]
}
You don't need to understand any of this, but what it means is that
if you use the angular.min.js file in a web page, and also make
angular.min.js.map and angular.js files available, when you debug
with a sourcemap-enabled debugger (like Chrome Dev Tools), you'll see
the original source instead of the minized source.
But there are a few issues. Although I haven't written any tools to generate
source maps, I do consume them in libraries and with tools that I use
(like browserify). Sometimes I do a bit of
surgery on them, to make them work a little better.
Armed with this experience, I figured I'd post a few "best practices", based
on some of the issues I've seen, aimed at folks generating sourcemaps.
do not use a data-url with your sourceMappingURL annotation
Using a data url, which browserify does, ends up creating a huge single line
for the sourceMappingURL annotation. Many text editors will choke on this,
if you accidently, or purposely edit the file with the annotation.
In addition, using a data-url means the mapping data is uuencoded, which
means humans can't read it. The sourcemap data is actually sometimes interesting
to look at, for instance, if you want to see what files got bundled with
browserify.
Also, including the sourcemap as a data-url means you just made your "production" file bigger, especially since it's uuencoded.
Instead of using a data-url with the sourcemap information inlined, just provide
a map file like angular does (described above).
put the sourceMappingURL annotation on a line by itself at the end
In the angular example above, the sourceMappingURL annotation is in a // style
comment inside a /* */ style comment. Kinda pointless. But worse,
it no longer works with Chrome 31.0.1650.8 beta.
Presumably, Chrome Dev Tools got a bit stricter with how they recognize the
sourceMappingURL annotation; it seems to like having the comment at the
very end of the file. See https://code.google.com/p/chromium/issues/detail?id=305284
for more info.
Browserify also has an issue here, as it adds a line with a single semi-colon
to the end of the file, right before the sourceMappingURL annotation, which
also does not work in the version of Chrome I referenced.
name your sourcemap file <min-file>.map.json
Turns out these sourcemap files are json. But no one uses a .json file extension,
which seems unfortunate as the browser doesn't understand them, if you happen
to try loading one of the files there. Not sure if there's a restriction about
naming them, but it seems like there shouldn't be, and it seems like it makes
sense to just use a .json extension for them.
embed the original source in the sourcemap file
Source map files contain a list of the names of the original source files
(urls, actually), and can optionally contain the original source file content
in the sourcesContent key.
Not everyone does this - I think most people do not put the original source
in the sourcemap files (eg, jquery, angular).
If you don't include the source with the sourcesContent key, then the source
will need to be retrieved by your browser. Not only is this another HTTP GET
required, but you will need to provide the original .js files as well as the
minized .js files on your server. And they will need to be arranged in whatever
manner the source files are specified in the source map file (remember, the
names are actually URLs).
If you're going to provide a separate map file, then you might as well add
the source to it, so the whole wad is available in one file.
generate your sourcemap json file so that it's readable
I'm looking at you, http://code.jquery.com/jquery-2.0.3.min.map.
The file is only used at debug time, it's unlikely there's going to be
much of a performance/memory hit by single-lining the file. Remember,
as I said above, it's often useful to be able to read the sourcemap
file, so ... make it readable.
if you use the names key in your sourcemap, put it at the end of the map file
Again, sourcemap files are interesting reading sometimes, but the names key
ends up being painful to deal with, if you generate the sourcemap with
something like JSON.stringify(mapObject, null, 4) or something. Because
the value of the names key is an array of strings, and it's pretty long,
as is not nearly as interesting to read as the other bits in the source map.
Add the property to your map object last, before you stringify it, so it
doesn't get in the way.
where can we publish some sourcemap best practices?
I'd like to see somewhere we can publish and debate sourcemap best practices.
Idears?
bugs opened
Some bugs relevant to the "sourceMappingURL not the last thing in the file" issue/violation: