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.
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:
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.[http://127.0.0.1:9229/json](http://127.0.0.1:9229/json)
Ā . This allows agents like the Chrome DevTools to know about every running Node session and their respectiveUUID
Ā .You can curl
[http://127.0.0.1:9229/json](http://127.0.0.1:9229/json)
. More information here:
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](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...
ā¦ 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.
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.
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:
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:
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.
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 šš«!
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! š