Building a new JavaScript linting experience in Visual Studio

Maria Solano

Available today in the 17.4 public release, Visual Studio has revamped its ESLint support! The new linting experience includes: 

  • Linting support – for not only JavaScript and TypeScript files, but also for JSX/TSX, Vue and HTML files. 
  • Quick actions and fixes, which allow you to auto-fix errors or disable ESLint rules on a single line or an entire file. 
  • Flexible global defaults under Tools -> Options -> Text Editor -> JavaScript/TypeScript -> Linting that are overridable with project configuration.
  • A guiding installation wizard that will help you set up your ESLint configuration and dependencies based on your project. 

But the main purpose of this post is not to list all of the cool things that the new linting service provides, but to tell you a little bit about the story behind it. I joined Microsoft at the beginning of 2022, and as an eager software engineer on the fantastic TypeScript tooling team, I was curious about what my first large project might be. 

It all started when adding support for the latest version of ESLint, the popular JavaScript linter. ESLint 8 had a few breaking changes in its linter interface, and that required an update in Visual Studio’s integration. While working on the fix, I realized that our implementation had not been updated in a while and was missing several features that other IDEs offered. This was the opportunity I was looking for: We would bring out the full power of ESLint in Visual Studio, creating a new linting experience for our users! As a beginner C# developer that had never ventured into Visual Studio’s extensibility APIs (I would often scratch my head wondering what MEF was), I had no idea of where to begin. However, from my web development past, I knew how important those squiggles were and how much they impact the programming experience when writing JavaScript code, and so I ignored my fears and thrived to deliver the squiggles I would like to have myself.

 

An LSP extension inspired from vscode-eslint

The goal was for the linting experience in Visual Studio to be on par with the one in VS Code. The editor’s support for disabling ESLint rules, auto fixing errors, and the settings available for tuning the linter’s behavior are highly beloved features by VS Code users.

Fortunately, there was a linting server providing this functionality, and a protocol on how to communicate with it. The extension powering VS Code’s ESLint support is vscode-eslint, which is often featured as one of the most beloved extensions for JavaScript and TypeScript development. vscode-eslint is an LSP (Language Service Protocol) extension, with a server handling linting requests and a client that communicates with the editing tool to display the server results. For example, if the user opens a JavaScript file, the LSP client will notify the server that a document of interest has been opened, the server will compute the linting errors and send them back to the client, and then the client will provide the core editor with diagnostics to display in the document and error list. Thanks to the standardized communication defined by the language server protocol, a single server can be re-used in multiple development tools, and tools can support new extensions with minimal effort. 

The LSP-based architecture of vscode-eslint meant that our goal was feasible: Visual Studio’s linting integration could be of the same quality as VS Code’s, since they could use the same server behind the scenes. We still had to write the Visual Studio client, which would make those linting squiggles show up in the editor. 

I don’t want to bore you with all the technical details (mostly because they involve me debugging JSON error responses), but I do want to mention some of the things we learned from this experience: 

  • Extensions should feel natural to its host. The VS Code extension relies on workspace configurations for storing local linting settings, but most Visual Studio developers use projects and solutions to organize their code. We then decided to use project properties for these local settings, respecting the IDE’s essence. 
  • Documentation is key. From the LSP specification listing the relevant requests that our client had to handle, to the fantastic extensions from our dear Mads that illustrate how to use several of Visual Studio’s extensibility services. Implementing this feature motivated me to also give back to the extensibility community, and now I try to improve existing documentation (or add new one) that captures the things I learn. 
  • LSP extensibility is amazing. It might be a bit of a learning curve to get started, but it abstracts the specifics of the editor’s implementation (no need to implement a custom ITagger to provide error squiggles!), allowing you to build a reusable and more compact extension. 

 

Using the new linting service

To get started with ESLint in your project, you’ll first need to install the npm module by running npm install –dev eslint in the command line. You might need to install additional linting plugins; for example, you may need TypeScript ESLint, which enables ESLint to run on TypeScript code and includes rules that are specific to the extra type information. 

Once you have the necessary dependencies installed, enable ESLint in Tools > Options > Text Editor > JavaScript/TypeScript > Linting, and include an .eslintrc file to customize your linting configuration. The ESLint website has great documentation about how to use this file. 

And that’s it! You should now be able to see error squiggles when your code doesn’t follow your linting rules:

Linting error diagnostic

By right-clicking on the squiggle and viewing the available quick actions, you’ll be able to disable the error or fix it! 

Linting error squiggle

 

Next steps

You can try out the new linting experience in Visual Studio 17.4 (note that linting in Vue and HTML will be available in the next release). Make sure to review the documentation for detailed instructions on the required setup, and please submit a feedback ticket if you encounter any issues or have an idea of what other linting enhancements you would like to see in Visual Studio. 

Enjoy your squiggles! 

3 comments

Discussion is closed. Login to edit/delete existing comments.

  • Stuart Ballard 1

    This is fascinating to read about. I worked on a project for over two decades which had some files using my own custom syntax, and I always low-key hoped to eventually add syntax highlighting and IntelliSense for them. Sadly that project is no more and I’ll never actually get to do it, but my interest in the topic lives on.

    I’m curious about the division of responsibility between client and server when it comes to LSP: I’d naively imagined that once an LSP service existed, it could be used immediately by any IDE which understands the protocol, but from your article it sounds like that’s at best an oversimplification, if not outright wrong. You mentioned management and storage of user settings, which makes sense; are there other areas where the IDE client needs customized code for each individual LSP?

    • Maria SolanoMicrosoft employee 0

      Glad to hear that you enjoyed the post!

      To answer your question, another good example where LSP client code is often specific to each editor is the display of diagnostics. Notice how in VS Code errors in the “Problems” pane can be displayed in a tree or table view, and the information about the error (like the code in location) is shown in a different way for each view. In VS, diagnostics are listed in the error list, and there are extra columns that don’t appear in VS Code (like the “Project” and “Suppression state” columns). Editors can offer extensions like this to accommodate for these extra features.

  • Holger Jeromin 1

    This really rocks!
    No more waiting 20 seconds for eslint updates in the editor. Thank a lot for your work.

Feedback usabilla icon