Debugging ES6 in Visual Studio Code
Debugging ES6 Javascript code in the Visual Studio Code IDE can be a painful process to setup. In this article we’ll walk through one way to set it up and get productive.
The challenge to getting this working is rapid rate of change of the Javascript language, the Javascript transpilation tooling as well as the Visual Studio Code configuration interface. Both have changed drastically in the last year, rendering most previous tutorials and blog posts out-of-date. For example, this excellent gist was the basis for much of this article, but it’s written against the 1.0 version of vscode’s launch.json
and tasks.json
specification.
Let’s run down the characteristics of the application we’d like to debug:
- Written in ES6, transpiled to ES5 with
babel-cli
- Imports other internal files, as well as external dependencies
- Uses an executable file (via
chmod +x
) as an entry point
Let’s also take a look at the package.json
that implements the transpilation in various scripts. Note that our application files reside in src/bin
and are transpiled to dist/bin
, while the lib files it loads reside in src
and are transpiled to dist
.
It’s important that you generate source maps for your ES6 code — in the code above we pass the --source-maps
switch to the babel
tool to generate *.map
files alongside the transpiled ones in the dist
directory. You may also generate inline maps by using --source-maps inline
instead.
We also need to specify what environment we’re targeting with our babel
transpilation. Create a file named .babelrc
in your root folder. We’re going to use the babel-preset-env
module to target a recent version of Node.
We should now have all of the tools to write our launch.json
:
Note that we’re invoking npm run build
via the preLaunchTask: "npm: build"
property in the launch config. That way every time we debug we know we’re running the latest and greatest transpiled code. If you haven’t worked with the Visual Studio Code Tasks system before, it’s worth noting that vscode recognizes an npm project via the presence of a package.json
and automatically configures Tasks based on the items in the scripts
config. In our package.json
we have a build
task that removes the current dist
directory and rebuilds both the lib and bin source with the correct configuration for each. We can refer to these auto-generated Tasks in our launch configuration by the names that vscode generates (hence why npm run build
becomes npm: build
in the launch config.
That should be it! You should now see the Debug Increment Command launch configuration when you switch to the Debug view in Visual Studio Code.
Clicking on the green Start Debugging button to the left of the launch configuration should run npm run build
first and then launch the app under the debugger. If you set no breakpoints it will likely just run and end, unless you set stopOnEntry: true
in the launch configuration.
Set some breakpoints in src/bin/app.js
and hit the Start Debugging button again and we should now see execution halt at the breakpoint and give us all the goodies we want out of a visual debugger (local variables, watch window, call stack, console, etc.)
This tutorial may be helpful and up-to-date for anywhere between 14 nanoseconds and 6 months as the various tools change, but for those writing npm modules with possible bin scripts included this is the best way that I know of right now to be able to write ES6 code while delivering and debugging the transpiled ES5 equivalent functionality.
Happy debugging!
UPDATE: Thirty-two minutes after I posted this, my prophecy was realized and the September 2017 update to Visual Studio Code was released, deprecating the usage of ${workspaceRoot}
in launch and task configurations. If you have updated to version 1.17.0 or newer of vscode, then you should now use ${workspaceFolder}
instead.
Zachery Moneypenny is a Principal Developer at adorable.io. Rubyist for a long time, with experience in Golang and Javascript as well but moving towards Elixir and loving it.