Monday, February 2, 2015

Debugging Nashorn JavaScript with Intellij

I recently started experimenting with JavaScript inside of the Nashorn container. I soon realized that I needed to find a debugging solution. A quick search on the Web found what I was looking for: Intellij added the support in version 13.

Unfortunately initial attempts at debugging with Intellij hit some roadblocks. The support was only working for the simplest of configurations for me. The main problems for me were:
  • Absolute file paths didn't work.
  • Multi-module projects didn't work. The breakpoints would be be hit but the source would not be shown.
  • If my JavaScript came from another source, such as a Reader or CompiledScript, debugging wasn't available. The only pattern that seemed to work was engine.eval("load 'filename')". Unfortunately this didn't match my use case.
After some experimenting I was luckily able to overcome most of my problems. It would be nice if some enhancements were added to Intellij, but at least I was able to function.

Script Paths
Intellij only works with relative path names. If the JavaScript is located within the project tree then it is pretty easy to convert an absolute path to a relative path in your code. If, however, the JavaScript resides outside the project directory tree, you are pretty much hosed. It would really be nice if Intellij implemented a more robust matching algorithm. If the filename (without path) matches something in your project tree then Intellij could prompt you to confirm the match.

Multi-Module Projects
The trick to making multi-module projects work is to understand the algorithm Intellij uses to match up the source with a debugging breakpoint. I discovered that Intellij always matches by using a relative file path relative to the root of the project tree rather than the root of the module in which the source resides. Adjusting your relative path name to be relative to the project root works around this problem. Again, it would sure be nice if the IntelliJ matching algorithm was smarter.

JavaScript from another Source
Intellij needs to be able to match up the JavaScript breakpoint with its source. If your code is using a Reader as for script input then Intellij Has no clue what to do.  I found the solution to this is to add to your JavaScript a hint about the JavaScript file name. You can add a line at the front of your JavaScript like this:
//@ sourceURL=pathRelativeToProject/name.js
Dynamically Downloaded Source
A related problem I had was for source being dynamically downloaded from another location. To solve that problem I had to do something special. If in debugging mode, I create a temp directory within the directory tree of my project and copy the dynamically downloaded javascript into that directory. While writing the JavaScript to the local file system, I prepend the "//@ sourceURL" statement for its new temporary location. This makes everything work just fine.