ClojureScript Source Maps

15 September 2013

UPDATE: This is now an outdated post. For more accurate information on enabling source maps please refer to the ClojureScript Wiki entry.

ClojureScript has had experimental source map support for some time. Unlike other transpile to JavaScript languages, ClojureScript source maps actually map all the way through Google Closure advanced compilation! However this support suffered from inaccuracies due to the lack of necessary information from the Clojure reader and less than ideal handling of function parameters and let bindings in the ClojureScript compiler. We switched to tools.reader, a wonderful library led by Nicola Mometto that works just like the standard reader but provides the needed line and column information on all symbols. Then we received a patch this weekend from Sean Grove that fixed an off by one error and changed the compiler to properly emit function parameters and let binding. With these things in place we can finally emit accurate source maps. There's likely more issues but the only way to find out is to give it a try and file some bug reports!

In order to enable source maps your project.clj should look something like this:

(defproject example "0.1.0-SNAPSHOT"
:dependencies [[org.clojure/clojure "1.5.1"]
[org.clojure/clojurescript "0.0-1889"]]

:plugins [[lein-cljsbuild "0.3.2"]]

:cljsbuild
{:builds
:source-paths ["src/example"]

Currently the source map generated by the ClojureScript compiler uses full paths for the files. How to best configure this is up for discussion as some files live in JARs and ClojureScript doesn't always write out these files to :output-dir. Perhaps it should but that's the kind of feedback we're looking for and the kind of patches we're interested in.
In the meantime you can still test out the feature as we've hacked the ClojureScript browser REPL web server to handle serving files from JARs and elsewhere! So just make sure source maps are enabled in your browser of choice, make an index.html file that includes your ClojureScript output file, run lein trampoline cljsbuild repl-listen and point your browser at http://localhost:9000.
If you get it working you should be able to console.log something and the browser will give you an accurate location where that statement was executed in the original source: