Nodemon + Babel + VSCode
I switched to VSCode as my primary editor almost a year ago. One of the primary reasons being that I could never get a Node debugger working quite right in Atom. Once I installed VSCode and figured out Launch Configurations it worked perfectly. Most of the tutorials for setting up node apps for debugging in VSCode either assume you are 1. not using nodemon or 2. not using babel. I use both, and want both to be a part of my workflow in addition to being able to use the built-in debugger.
After hours of tinkering, I figured out how to get Nodemon + Babel + VSCode Launch configurations to work. There are two parts to this setup: both package.json
and .vscode/launch.json
need to be updated.
package.json
{
"devDependencies": {
"babel-preset-es2015": "^6.24.1",
"babel-register": "^6.26.0"
},
"babel": {
"presets": [
"es2015"
],
"sourceMaps": true
}
}
Firstly, your project has to be setup to use babel either with a .babelrc
or a babel
key in the package.json
. Babel is going to be automatically invoked in this setup, which is why this is required.
Next, if you are only using the babel compiler before now, you’ll need to add babel-register
to your dev dependencies so compilation can happen on the fly. Why does compilation need to happen on the fly? This is so you can actually use breakpoints in your code. The compiled files will be mapped in memory, so you’ll never have to set breakpoints in a compiled file (which is a problem with some other solutions). Think of these as the minimum required settings since you’ll probably have more in your project.
launch.json
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Nodemon",
"runtimeExecutable": "nodemon",
"args": ["${workspaceRoot}/index.js"],
"restart": true,
"protocol": "inspector",
"stopOnEntry": false,
"runtimeArgs": [
"--nolazy",
"--require",
"babel-register"
],
"sourceMaps": true
},
]
}
Breaking it down
There’s a lot going on here, and I won’t cover the basics of working with launch configurations in VSCode but will point out the most important things to know.
There are four attributes that make this work:
- runtimeExecutable - This is the binary or script actually launched by VSCode. In this case it’s
nodemon
instead of your application. If you don’t havenodemon
globally installed you can reference the relative path with${workspaceRoot}/node_modules/nodemon/bin/nodemon.js
. - args - This represents the last argument passed to nodemon, so it should be the main file of your application. VSCode launch configs can’t inspect the
package.json
so this has to be hardcoded. If your application takes other arguments when it is launching, add those here after the main file, just like you would if you were callingnode ...
- runtimeArgs - This is the glue that holds all of this together. These arguments get passed in the order you specify to
nodemon
beforeargs
. Order is important, and these settings won’t work if they are inargs
. The--require
andbabel-register
need to be separate because arguments in this list cannot have spaces; you’ll get an error if you try to do that. - sourceMaps - VSCode needs to know about source maps. If this setting, or the one in
package.json
, is missing then you’ll get an error.
There’s one catch. There always is. When you stop via the stop button in VSCode, nodemon will crash. If you are using the integratedTerminal
instead of the debug console, you’ll need to CTRL+C
to exit. In older versions of VSCode (I’m running 1.19.3) the nodemon process would continue forever and eventually freeze VSCode, making it unusable. This isn’t ideal, but is better than it used to be and easy to work around.
Debugging
One of the things I realized early was that debugging this setup is non-trivial. Thankfully there is a setting you can add to the root of your launch.json
file that will print a lot of useful information: "diagnosticLogging": true
.
{
"version": "0.2.0",
"diagnosticLogging": true,
"configurations": [
...
]
}
Once set, this will output extra information about what’s going on. Mostly we’re interested in the actual nodemon
command that’s being run:
/usr/local/bin/nodemon --nolazy --require babel-register --inspect=42894 --debug-brk index.js
Debugger listening on ws://127.0.0.1:42894/cbdd92cd-4841-4b70-ad8c-99b8d5f0bbd0
Debugger attached.
If you’re having trouble getting your app to start, this is an invaluable tool. Note also how runtimeArgs
are inserted in the middle of the command, in the order in which you added them. This is how I figured out how to inject babel-register
, since those arguments are always added in order.
This VSCode setup has helped me immensely, and I hope it helps you too!