2019-06-15 Debugging Node.js programs in a Vagrant virtual machine

One of the very nice things in a programmer’s toolbox is a debugger. Coming from Emacs, I am accustommed to Edebug, which allows to step through the code, install breakpoints (conditional ones as well as unconditional ones), watch variables etc.

Programming in JavaScript is (or at least should be) no different. Indeed, both Firefox and Chromium have a debugger in their DevTools (although Chromium’s one seems a tad more confusing). This is all good when I’m debugging front-end code, but I often work on some backend code in Node.js.

Fortunately, it can be debugged, too. There is the --inspect argument to node which allows for using Chromium to debug Node.js code. Here is how you can use it.

Let us first write a simple Node.js script:

console.log('Hello');
console.log('world!');

and save it as, say, /tmp/hello-world.js. Now, instead of saying node /tmp/hello-world.js, let’s say node --inspect /tmp/hello-world.js.

Well, (almost) nothing interesting happens, apart from two lines displayed by Node.js debugger. This is because there are no breakpoints in our code. We could insert a debugger directive in this code, but nothing would happen then. (I suspect that was because I didn’t manage to open the Chromium debugger fast enough and the code reached the debugger directive before connecting to Chromium. In such a case, it is ignored. At least, a short experiment with a suitable sleep confirms this conjecture.) However, we can also use the --inspect-brk argument, which sets a breakpoint right at the beginning of our script.

How do we now attach the Chromium debugger to our script? Let us run node --inspect-brk /tmp/hello-world.js and then switch to Chromium. After pointing it to the chrome://inspect url, we click the Configure... button and add a row of the form localhost:9229. Bingo! Two links appear now: Open dedicated DevTools for Node and inspect, right below the filename of our script. I have honestly no idea whether there is any difference in clicking either of the two, but even if not, I’d prefer the second one, since at allows to choose the script in an unlikely event of debugging two scripts at once.

Now that we click inspect, a DevTools window should open and show our code. Congratulations! We can now step through the code, view (and even change!) variable values etc.

Well, this is all good and fun, but in reality, I faced one more problem. Most of the Node.js code I have is executed in a virtual machine (we use Vagrant and VirtualBox). I thought that I could just edit Vagrantfile to enable port forwarding, so that guest’s port 9229 is forwarded to e.g. 9221 on the host machine. Unfortunately, for some reason I could not make it work. Luckily, there is another way.

As the friendly manual suggests, we can use ssh’s -L option, which is another way of setting up port forwarding. We can now say e.g. vagrant ssh -- -L 9221:localhost:9229 (and add localhost:9221 to the Chromium inspect configuration; of course, nothing stops us from using 9229 on both the host and guest machines, too). Now we can just run node --inspect-brk on the VM, and Chromium inspector just works. That’s it!

There is one more thing that can be said here: we can use some other client instead of Chromium. There are a few such clients. One is built into Node.js (just say node inspect hello-world.js and see what happens – this looks a bit crude, but hey, it’s terminal based!). Of course, there is another one (Indium), which I hope to experiment with, since it is Emacs-based.

CategoryEnglish, CategoryBlog, CategoryJavaScript