Using VS Code for JavaScript

By Orta Therox

I’m an old school TextMate user, who has also been using Xcode for the last decade. These two sit at a very opposite ends of an “editor” spectrum.

TextMate is extremely bare bones at the core, but introduced the idea of bundles as plugins. Making it really easy for others to build their own plugins for their own contexts. Xcode on the other-hand includes a 3D scene editor, the best interface builder I’ve seen, super rich debugging tools and close to zero support for improving it yourself.

As we agreed on moving to React Native, we needed to decide what the team should use for working in that environment. After experimentation with many editors, we decided on Microsoft’s Visual Studio Code.

We wanted to keep a lot of the best features from Xcode, while working in a completely JavaScript environment. For example: debuggers, inline errors, auto-complete, symbol mapping and to ideally have them all inside a single editor.

Let’s dig into the principals of how Visual Studio Code works, what makes it a better option for us, and what parts of it really shine.

What is Visual Studio Code?

Visual Studio Code (VS Code) is yet another, JavaScript-based text editor. It’s built atop of GitHub’s Electron. Electron is a framework for writing native apps as easy as building websites. It started as a web component for some Microsoft web-service, and eventually evolved into a fully-fledged text editor.

IDE - Editor hybrid

Visual Studio Code (VS Code) believes that the sweet-spot between and IDE and a plain Text Editor, is somewhere a little bit closer to the IDE side.


This means instead of the Text-Editor style folder based approach, VS Code expects to set up a project structure per-project to start supporting from of the more useful IDE-like features.

It supports TextMate style plugins (called Extensions) through a controlled, but expanding extension API. The extension API work takes an Apple-like approach to ensuring stability by having all extensions run outside of the host process. This approach ensures any extension crash does not take down the editor.

It’s also smart about deciding when to load an extension, for example, my Danger extension will only load if there is a Dangerfile in the root of the workspace.

These two approaches to extensions are specifically aimed at addressing issues seen inside Atom, where any user actions can be / are blocked by extensions, and extensions have full-reign to make any change they want. Even on my Mac Pro, there is a noticable lag. I initially assumed this was the “JavaScript tax” for all Electron apps, but VS Code is fast.

Making Intellisense

By default a JavaScript project does not have a way to provide auto-completion, or in VS Code’s terminology: Intellisense. Trying to make auto-complete based on a REPL can only get you so far, because it has to be wary against functions with side-effects. Other alternatives are to build an AST from the code, and then introspect that.

In Xcode the auto-complete tools are powered by the type systems of Objective-C and Swift. This means that you can know the structure of an object, without having to dig inside it, potentially breaking it in the process. Vanilla JavaScript does not have a type system. There are a few root classes though: String, Object, Number etc.

To work around this problem, VS Code uses TypeScript behind the scenes. TypeScript is a language that compiles down to JavaScript which provides a typing structure on top of JavaScript. This is a similar approach to how Flow works too, which is the language we write React Native in.

This can work out really well for your own classes if you are declaring your types, but the npm ecosystem is full of untyped JavaScript, and a lot of your work is about sitting atop those abstractions. The fix for this is offered via DefinitelyTyped which provides type definitions for popular npm modules. For example here is one for Redux - these act like header files in Objective-C - offering inline documentation, and the shape of the object.

I use an extension to keep these up to date and to have them installed in every project I work in: Types auto installer. Here’s an example of auto-complete for a Redux store.


It’ll also provide information about the parameters, which is a life-saver for me. Having grown up with named parameters.

Redux Params


Using console logs to debug isn’t an acceptable answer when debugging for me anymore. That’s churn that I’m not willing to lose time to. Luckily for me, VS Code supports debugging across many languages.

It does this by having a generic VS Code Debug Protocol which lets extensions use their own processes to run the debugger. So the ruby debugger runs on the ruby-debug-ide gem, and for node-based projects it uses the debugger built into node.

So, here is a common case. I want to start up my web-server, so I need to run npm dev. I can run this from VS Code:


Once that’s running - I can attach a debugger. This is listing all of the available node processes on my computer:


Then I can add a breakpoint, and when it is triggered, I have a full stack trace and REPL. The REPL is very barebones, for example - there’s no auto-complete. However, it’s good for quick exploration. I keep accidentally prefixing my REPL code with po.


The breakpoint works through a source map, and so the line you expect is the one that you’re working in. That stuff is all pretty magic to me. Good on Microsoft, and the node community for pulling that off.


I still feel a little bit uncomfortable in JavaScript projects, as a long-time native developer. However feel like VS Code is a nice mix of the freeform “just do something” style of Text Editors, which work across a lot of systems and the tight-knit IDEs that are bound to a specific domain. It can be a bridge between worlds.

VS Code has become my main editor in Ruby and JavaScript, due to having great support for the projects and being an OSS project which I feel like I can contribute to. No more being locked out of improving my editor. Awesome!