{"id":551237,"date":"2025-03-06T19:26:00","date_gmt":"2025-03-06T18:26:00","guid":{"rendered":"https:\/\/blog.jetbrains.com\/?post_type=webstorm&#038;p=551237"},"modified":"2026-01-16T19:16:11","modified_gmt":"2026-01-16T18:16:11","slug":"the-angular-language-server-understanding-ide-integration-approaches","status":"publish","type":"webstorm","link":"https:\/\/blog.jetbrains.com\/zh-hans\/webstorm\/2025\/03\/the-angular-language-server-understanding-ide-integration-approaches","title":{"rendered":"The Angular Language Server: Understanding IDE Integration Approaches"},"content":{"rendered":"\n<p>The Language Server Protocol (LSP) has been a fundamental part of the code editor landscape for years, providing a consistent development experience across different editors. The Angular Language Server leverages this protocol to provide Angular-specific features to compatible editors. However, not all IDEs take the same approach to delivering these capabilities. Let\u2019s look at the major differences between VS Code, NeoVim, and WebStorm and finally answer the age-old question, \u201cWhy does WebStorm not just use the Angular Language Server?!\u201d<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>What is a language server, and how does the LSP work?<\/strong><\/h2>\n\n\n\n<p>Modern code editors need to understand your code to provide features like autocompletion, go to definition, or error detection. Traditionally, each editor needed to implement this understanding for every programming language, leading to duplicated effort and inconsistent experiences across editors.<\/p>\n\n\n\n<p>The Language Server Protocol (LSP) solves this by standardizing how editors communicate with language-specific analysis tools. Here&#8217;s how it works:<\/p>\n\n\n\n<ol>\n<li>Your editor (the client) sends information about your code (typically the file that is currently open in your editor) to a language server.<\/li>\n\n\n\n<li>The language server analyzes the code and responds with insights.<\/li>\n\n\n\n<li>Your editor displays these insights as squiggly error lines, autocompletion popups, or other UI elements.<br><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\">\/\/ When you type this in your editor\n@Component({\n  template: `\n    &lt;div *ngFor=&quot;let item of items&quot;&gt;\n      {{ item.property }}\n    &lt;\/div&gt;\n  `\n})\nclass MyComponent { }<\/pre>\n\n\n\n<p>Your editor sends the file content to the language server. The server analyzes it and might respond with:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\">{\n  &quot;diagnostics&quot;: &#091;{\n    &quot;message&quot;: &quot;Property &#039;property&#039; does not exist on type &#039;any&#039;&quot;,\n    &quot;range&quot;: {\n      &quot;start&quot;: {&quot;line&quot;: 3, &quot;character&quot;: 12},\n      &quot;end&quot;: {&quot;line&quot;: 3, &quot;character&quot;: 20}\n    }\n  }]\n}\n\/\/ Your editor then shows the error underline<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">This standardization means that:<\/h2>\n\n\n\n<ul>\n<li>Developers of editors and IDEs can add support for new languages just by implementing the LSP client once.<\/li>\n\n\n\n<li>Language tool developers can support all LSP-compatible editors with a single server and very small client implementations (JetBrains IDE plugin or VS Code plugin).<\/li>\n\n\n\n<li>Developers get consistent features across different editors.<\/li>\n<\/ul>\n\n\n\n<p>The Angular Language Server specifically provides Angular-aware code analysis, offering features like template type checking, component property completion, and Angular-specific refactorings to any editor that supports LSP.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Benefits of the Language Server Protocol<\/strong><\/h2>\n\n\n\n<p>The LSP has established itself as the standard for providing editor intelligence across different development environments. It enables consistent features like type checking, code completion, and navigation across any LSP-compatible editor:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\">@Component({\n  template: `\n    &lt;div *ngFor=&quot;let item of items&quot;&gt;\n      {{ item?.deeply?.nested?.property }}\n    &lt;\/div&gt;\n  `\n})\nclass WhyTypeCheckingMatters { }<\/pre>\n\n\n\n<p>While the Angular compiler would catch these template errors during build time, the language server provides immediate feedback in your editor. This means you can spot and fix type errors as you write your code, without waiting for the compilation step.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>VS Code: LSP&#8217;s golden child<\/strong><\/h2>\n\n\n\n<p>VS Code&#8217;s integration with the Angular Language Server is seamless and intuitive. Here are some of the features that you\u2019ll be able to use after installing the <a href=\"https:\/\/marketplace.visualstudio.com\/items?itemName=Angular.ng-template\" target=\"_blank\" rel=\"noopener\">necessary plugin<\/a>:<\/p>\n\n\n\n<ol>\n<li><strong>Template type checking:<\/strong> Because nobody likes finding out about undefined properties in production.<\/li>\n\n\n\n<li><em>Go To Definition<\/em>: Jump straight to your TypeScript references.<\/li>\n\n\n\n<li><strong>Autocompletion:<\/strong> For when you can&#8217;t remember the syntax of <strong><code>*ngFor<\/code><\/strong> or <strong><code>@switch<\/code><\/strong>.<\/li>\n\n\n\n<li><strong>Real-time error detection:<\/strong> Catch those typos before they catch you out.<\/li>\n<\/ol>\n\n\n\n<p>The best part? It&#8217;s all standardized. The same language server that powers VS Code can power any editor that speaks LSP.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Neovim: for when Vim users want nice things, too<\/strong><\/h2>\n\n\n\n<p>Remember when Vim users had to type out every import statement manually? Pepperidge Farm remembers. Now, thanks to LSP, you get:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\">-- Neovim config that actually gives you IDE features\nrequire&#039;lspconfig&#039;.angularls.setup{\n  -- Look ma, real autocomplete!\n}<\/pre>\n\n\n\n<p>Neovim users now enjoy the same powerful features as VS Code users while keeping their beloved modal editing. It&#8217;s the best of both worlds \u2013 modern IDE features with an outstanding editing experience.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>The caveats of language servers<\/strong><\/h2>\n\n\n\n<p>Language servers are great \u2013 they provide a consistent developer experience and guarantee correctness. However, the fact that language servers adhere to a standardized protocol means that they do have some limitations. For instance, even though most languages and frameworks have some kind of test support,<a href=\"https:\/\/github.com\/microsoft\/language-server-protocol\/issues\/1267\" target=\"_blank\" rel=\"noopener\"> the LSP is not aware of this concept<\/a>, and, therefore, tests must be configured manually within the editor. This is also the case when working with debuggers, too.<\/p>\n\n\n\n<p>Additionally, language servers generally look at the codebase on a \u201cfile by file\u201d basis, and, more specifically, at the current cursor position. Generally speaking, this works great until it doesn\u2019t\u2026 Implementing a multi-file refactoring, for instance, can be difficult (though not impossible). For this reason, extracting some HTML code into a new Angular component is not as straightforward as it might first sound. On top of that, language servers can usually only process one language at a time; therefore, refactoring a CSS class across languages can quickly become very cumbersome in a language server implementation. The Angular Language Server has a very clever trick for handling HTML and TypeScript, but more on that in the next section. CSS, on the other hand, doesn\u2019t enjoy the same level of support.&nbsp;<\/p>\n\n\n\n<p>What\u2019s more, adding further support for parts that don\u2019t have dedicated compiler functionality is difficult to accomplish. One such example would be IntelliSense for the<a href=\"https:\/\/github.com\/angular\/vscode-ng-language-service\/issues\/1730\" target=\"_blank\" rel=\"noopener\"> host property<\/a> of the component decorator.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>WebStorm: a slightly different approach<\/strong><\/h2>\n\n\n\n<p>Now, here&#8217;s where things get interesting. <a href=\"https:\/\/www.jetbrains.com\/webstorm\/\" data-type=\"link\" data-id=\"https:\/\/www.jetbrains.com\/webstorm\/\" target=\"_blank\" rel=\"noopener\">WebStorm<\/a> and other JetBrains IDEs take a different approach, and it&#8217;s not just about being contrarian. For the last few years, the Angular plugin has been pre-installed with WebStorm. As of now, this plugin does not utilize the Angular Language Server, but a custom-type engine. As part of our<a href=\"https:\/\/blog.jetbrains.com\/webstorm\/2023\/12\/try-the-future-typescript-engine-with-the-webstorm-next-program\/\"> new Service-powered type engine (more about this in the future), <\/a>we made some major changes to our Angular integration. Instead of using the entire Angular Language Server, WebStorm adopted Angular\u2019s TCB (type-check block) engine, an integral part of the Angular Language Server. For more details, you can check out this<a href=\"https:\/\/www.youtube.com\/watch?v=_ccNQTLmxe8\" target=\"_blank\" rel=\"noopener\"> talk at NG DE<\/a>, but in short, the Angular Language Server converts the HTML code into TypeScript code and uses the generated TypeScript code to map errors and IntelliSense features back to the cursor position in the original HTML file. The screenshot below visualizes this concept.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" width=\"1600\" height=\"801\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/03\/Screenshot-2025-03-03-at-12.22.40-PM.png\" alt=\"Screenshot of WebStorm, showing a regular Angular Component with some unknown property error on the left side, whereas the right side shows the translated typescript code.\" class=\"wp-image-551238\"\/><\/figure>\n\n\n\n<p>See how <code>this.counter<\/code> is used in the template, which gets converted to the function <code>_tcb1<\/code> on the right side, but isn\u2019t properly declared in <code>TestComponent<\/code>.&nbsp;<\/p>\n\n\n\n<p>You might now be asking, why doesn\u2019t WebStorm just use the Angular Language Server? Well, it turns out template type checking is just one piece of the IDE puzzle. WebStorm&#8217;s architecture already handles most of what the Angular Language Server provides:<\/p>\n\n\n\n<ul>\n<li>Navigation<\/li>\n\n\n\n<li>Code completion<\/li>\n\n\n\n<li>Quick-fixes<\/li>\n<\/ul>\n\n\n\n<p>Furthermore, it offers parts of functionality that our users appreciate and that are not offered by the language server:<\/p>\n\n\n\n<ul>\n<li>Unit and E2E test integration for Jasmine, Jest, Vitest, Cypress, and Playwright.<\/li>\n\n\n\n<li>Debugging integration.<\/li>\n\n\n\n<li>Semantic highlighting of signals (fun fact: the Angular LSP does not provide syntax highlighting, which is part of the VS Code plugin).<\/li>\n\n\n\n<li>Special refactoring and <em>quick-fix<\/em> capabilities (e.g. <em>extract Angular Component<\/em>, <em>create a signal \u2018property\u2019<\/em>, etc.).<\/li>\n\n\n\n<li>IntelliSense without compiler support, like the host property mentioned above.<\/li>\n\n\n\n<li>Enhanced search capabilities (e.g. <em>Find Usages<\/em> for components).<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>The real-world implications<\/strong><\/h2>\n\n\n\n<p>So what does this mean for you, the developer, just trying to get work done?<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>VS Code and Neovim users<\/strong><\/h3>\n\n\n\n<ul>\n<li>Standardized experience across editors<\/li>\n\n\n\n<li>Regular updates with Angular releases<\/li>\n\n\n\n<li>Built-in type correctness<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>WebStorm users<\/strong><\/h3>\n\n\n\n<ul>\n<li>Built-in integration of broader IDE tools (debugger, test runner, run configurations, etc.)<\/li>\n\n\n\n<li>Direct TCB integration for template type checking<\/li>\n\n\n\n<li>Additional navigation, refactoring features, and consistent development experiences across different languages (HTML, CSS, and TypeScript)<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Looking forward<\/strong><\/h2>\n\n\n\n<p>The Angular Language Server continues to evolve, making developers&#8217; lives easier. Meanwhile, WebStorm&#8217;s specialized approach shows that there&#8217;s more than one way to achieve excellent Angular support.<\/p>\n","protected":false},"author":1424,"featured_media":551761,"comment_status":"closed","ping_status":"closed","template":"","categories":[6711],"tags":[2822],"cross-post-tag":[],"acf":[],"_links":{"self":[{"href":"https:\/\/blog.jetbrains.com\/zh-hans\/wp-json\/wp\/v2\/webstorm\/551237"}],"collection":[{"href":"https:\/\/blog.jetbrains.com\/zh-hans\/wp-json\/wp\/v2\/webstorm"}],"about":[{"href":"https:\/\/blog.jetbrains.com\/zh-hans\/wp-json\/wp\/v2\/types\/webstorm"}],"author":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/zh-hans\/wp-json\/wp\/v2\/users\/1424"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/zh-hans\/wp-json\/wp\/v2\/comments?post=551237"}],"version-history":[{"count":7,"href":"https:\/\/blog.jetbrains.com\/zh-hans\/wp-json\/wp\/v2\/webstorm\/551237\/revisions"}],"predecessor-version":[{"id":674822,"href":"https:\/\/blog.jetbrains.com\/zh-hans\/wp-json\/wp\/v2\/webstorm\/551237\/revisions\/674822"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/zh-hans\/wp-json\/wp\/v2\/media\/551761"}],"wp:attachment":[{"href":"https:\/\/blog.jetbrains.com\/zh-hans\/wp-json\/wp\/v2\/media?parent=551237"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/zh-hans\/wp-json\/wp\/v2\/categories?post=551237"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/zh-hans\/wp-json\/wp\/v2\/tags?post=551237"},{"taxonomy":"cross-post-tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/zh-hans\/wp-json\/wp\/v2\/cross-post-tag?post=551237"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}