Debugging ES6 in Visual Studio Code

Zachery Moneypenny
Adorable
Published in
4 min readOct 5, 2017
Photo by chuttersnap on Unsplash

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
Main application source
Command-line application wrapper

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.

.babelrc configuration

We should now have all of the tools to write our launch.json:

.vscode/launch.json configuration

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.)

Breakpoint hit: success!

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.

--

--

Zachery Moneypenny
Adorable

engineering manager at cars.com | opinions on tech interviewing | woodworking | song-and-dance man