Debugging JavaScript/TypeScript Node apps with Chrome DevTools, VS Code and WebStorm 🐞🔫

24,516 reads

This article covers using the Node Inspector to debug both JavaScript and TypeScript Node.js applications using Chrome DevTools, Visual Studio Code and WebStorm.

As described in the Node.js debugging guide, Node.js 6.3 introduced the “inspect” and “inspect-brk” CLI arguments ( node --inspect [file] or node --inspect-brk[file] ) that make node to listen via WebSockets for diagnostic commands as defined by the Chrome Debugging Protocol. This protocol has replaced the V8 Debugging Protocol (Now known as Legacy Protocol), which became obsolete on Node 7.7.

Additionally, the Node CLI also provides a “require” argument meant to preload modules ( node --require [file] ), but most importantly, for debugging purposes, it allows 3rd party libraries to hook into the “require.extensions” module and make Node able to compile and generate source-maps for other languages like TypeScript. For debugging TypeScript we’ll use ts-node. It’s important to remember that in your tsconfig.file , that can be generated by running tsc --init , you should have “sourceMap”: true , which is the default value.

I’ve prepared a GitHub repo with a simple Express app that calculates Fibonacci sequences. I recommend you to clone it to follow along, but this is not a requirement for continuing reading this article.

$ git clone https://github.com/andrerpena/medium-node-inspector-tests.git

$ cd medium-node-inspector-tests

$ npm i

I’ve also created scripts for all the commands we’ll run on this article. If you’re reading this without cloning the repo, use the following as a reference:

After your environment is set up, you should be able to npm start and access localhost:3000/[n] to see the Fibonacci sequences.

Because I wanted to showcase both JavaScript and TypeScript debugging, I’ve written the index.ts file first and the JavaScript version has been generated by tsc so it looks a bit ugly. You obviously won’t have this problem if your code is primarily written in JavaScript.

Running in Debug mode

We’ll explore 2 modes of debugging. Using --inspect and --inspect-brk . The difference is that the later will not actually start the execution of your code before an agent like Chrome DevTools is attached, and once it’s attached, it will automatically break at the first user-code line.

When a Node.js app is started in “inspect” mode, 2 important things will happen:

An UUID will be assigned to this debugging session and a WebSockets end-point will spin up at ws://127.0.0.1:9229/[UUID] . This end-point will stream real-time events with the current state of the running code. An HTTP end-point will spin up at http://127.0.0.1:9229/json . This allows agents like the Chrome DevTools to know about every running Node session and their respective UUID .

You can curl http://127.0.0.1:9229/json . More information here:

Debugging JavaScript using the Chrome DevTools

Run:

npm start:debug // if you're on the suggested repo or...

node --inspect index.js // ...otherwise.

You should see something like this:

You can see a WebSocket server has started on port 9229 . You can also notice the UUID is 5dc97... . Each session will have it’s own and every time you restart your server this will be different.

Next step is opening Chrome and entering Chrome://inspect on the address bar. You should see something like this:

Again, Chrome can automatically detect running sessions by inspecting http://127.0.0.1:9229/json . Now click Inspect to start debugging. A new DevTools window will show up. You can now navigate to the desired file, (e.g. by pressing Cmd + P on Mac), place your break-points and have fun 😄:

If instead, you run:

npm start:debug:brk // if you're on the suggested repo or...

node --inspect-brk index.js // ...otherwise.

… you’ll notice that localhost:3000 will not be immediately available. This is because, due to the --inspect-brk argument, Node will only start executing your code after the DevTools or another debugging agent is attached to give you the chance to place break-points beforehand. After clicking Inspect , you can now refresh localhost:3000 and it will automatically break on the first line of your code.

Debugging TypeScript using the Chrome DevTools

It should be almost the same thing we did with JavaScript except that now we should include --require ts-node/register when running Node. Run:

npm start:debug:ts // if you're on the suggested repo or...

node --require ts-node/register index.ts // ...otherwise.

And you should see this:

And when you start inspecting on Chrome://Inspect you should now see 2 versions of each TypeScript file: One with source-maps (marked as [sm] ) and another one without. Of course, place your break-points on the [sm] ones 😄:

Everything else should work exactly the same.

Debugging JavaScript using the Visual Studio Code

Just by selecting the target JavaScript file, clicking on the Debug tab ( Shift + Cmd + D on Mac) and hitting the ▶️ button should be enough to start debugging the current JavaScript file even without selecting any launch configuration . VS Code will automatically start Node with the --inspect parameter and attach to it.

You can also very easily create a launch configuration for attaching to a Node process running from the terminal. The VS Code auto-completion for configurations is amazing. This is how the configuration should look like. Remember that 9229 is the default port for the Node inspector:

Notice that the above configuration doesn’t specify the UUID of the Node session. VS Code, just like Chrome DevTools, will inspect ws://127.0.0.1:9229 and automatically attach to the current running session if there’s only one.

After the configuration is in place, run the usual start script from the terminal:

npm start:debug // if you're on the suggested repo or...

node --inspect index.js // ...otherwise.

… and then select Attach as the launch configuration and hit the ▶️ button:

Debugging TypeScript using the Visual Studio Code

VS Code, when using a configuration "type":"node" will not allow the program to be a .ts file (at least as this article is being written), then you’re left with 2 options: You can either run ts-node passing a .ts file as the argument ( ${relativeFile} returns the currently focused one)…

… or you can specify the runtimeExecutable to be NPM (instead of the default: node ) and pass a script name as an argument. Both of them have the exact same effect:

If you want, instead, to attach to a running TypeScript process spawn from a terminal, it is the exact same script we used for pure JavaScript. Just run the usual script on your terminal…

npm start:debug:ts // if you're on the suggested repo or...

node --require ts-node/register index.ts // ...otherwise.

… and then attach using the same script we used for pure JavaScript:

Debugging JavaScript using WebStorm

On the top-right corner of WebStorm there’s a dropdown where you can set up Run/Debug Configurations . Click on it and then select the ➕ sign to see a list of all available configurations. Select Node.js , give it a Name , and in the JavaScript file field, fill in your entry-point file. That is it. You can now hit the 🐞 button and the debug session should start.

Debugging TypeScript using WebStorm

In order to Debug TypeScript, the process is exactly the same as for JavaScript, except that, in the Node Parameters field, you should fill --inspect --require ts-node/register and select your TypeScript file in the JavaScript file field. You can start the debugging session as usual by hitting the 🐞 button.

I hope you enjoyed it and happy debugging 🐞🔫!

About the Author

I’m André Pena, I like writing and building stuff. Recently I built: https://remoted.io, a remote job aggregator for developers, check it out! 💗

Tags