Skip to content

Instantly share code, notes, and snippets.

@johnsoncodehk
Last active April 20, 2026 05:47
Show Gist options
  • Select an option

  • Save johnsoncodehk/62580d04cb86e576e0e8d6bf1cb44e73 to your computer and use it in GitHub Desktop.

Select an option

Save johnsoncodehk/62580d04cb86e576e0e8d6bf1cb44e73 to your computer and use it in GitHub Desktop.

Volar 2.0: The Rewrite

I'm Johnson, the author of Volar (now Vue Language Tools). We released 2.0 in March 2024. This is a look back at what we changed, why, and what it cost.

Why we needed to rewrite

Vetur and Volar v1 implemented Vue's IDE support through the Language Server Protocol. For small and medium projects this worked fine. For larger projects it broke down, and the reason was always the same: memory.

TypeScript Server and the Vue Language Server each kept their own copy of the project's TS AST — every file, every .d.ts in node_modules. When a project pulled in thousands of .d.ts files (common for anything with a big dependency tree), the two processes together could exhaust available memory.

TS Server            ██████████       516 MB
Vue Language Server  ███████████████  738 MB
                                      ─────────────
                                      Total: 1254 MB

It got worse. To make .ts files recognize .vue component types, and to support rename-across-files from .ts, users also had to install the TypeScript Vue Plugin — doubling the footprint again.

TS Server + Plugin   ████████████████████  much bigger
Vue Language Server  ███████████████        738 MB
                                            ─────────────────
                                            (nearly doubled)

Takeover Mode, and why it didn't work

The first fix I shipped was Takeover Mode. The idea was simple: if you manually disabled VSCode's built-in TypeScript extension in your Vue workspace, the Vue Language Server took over IDE support for .ts files too. One language server instead of two.

TS Server            (disabled)
Vue Language Server  ███████████████  738 MB
                                      ────────────
                                      Total: 738 MB

On paper, it solved the memory problem. In practice, Takeover Mode was barely used.

The discoverability was bad. To enable it, you had to:

  1. Find the list of built-in extensions in VSCode
  2. Locate "TypeScript and JavaScript Language Features"
  3. Disable it — per workspace, for every Vue project

If you didn't read Vue's documentation, you didn't know Takeover Mode existed. Even users who knew often didn't bother.

And the mode had deeper limits I kept running into:

  • No support for TypeScript LS Plugins
  • Features lagged behind VSCode's TypeScript integration
  • Every TS update risked a performance regression, because the TS auto-import cache kept changing shape
  • Invalidating that cache from our side was hard

It was a workaround. I spent a lot of v1 trying to make a workaround feel like a fix.

Hybrid Mode

In August 2023 I started asking a different question. If the TypeScript Vue Plugin could proxy TS functionality, why not put all TS features for Vue files inside that plugin?

TypeScript support for Vue files would come from the TS Server via the plugin. Everything else (CSS, HTML, JSON) would come from the Vue Language Server. Takeover Mode in reverse — except this time the user doesn't have to do anything.

The Vue Language Server no longer needs its own TypeScript instance. Memory usage lands in line with v1 Takeover Mode, without the configuration cost.

           ┌────────────┐
           │   Editor   │
           └──┬──────┬──┘
              │      │
         ┌────┘      └────┐
         ▼                ▼
 ┌───────────────┐  ┌─────────────────────┐
 │  TS Server    │  │ Vue Language Server │
 │               │  │                     │
 │  ┌─────────┐  │  │   CSS / HTML / JSON │
 │  │ Vue TS  │  │  │                     │
 │  │ Plugin  │  │  │   (no ts.Program)   │
 │  └─────────┘  │  │                     │
 └───────────────┘  └─────────────────────┘

        TS Server: 516 MB   Vue LS: 123 MB
                 Total: 639 MB

I wrote the PoC over four months.

PoC commit

In January 2024 we released Volar.js 2.0, carrying the infrastructure and refactoring Hybrid Mode required. The TS plugin migration for Vue went in as one PR.

Migration PR

The benchmark tells the cleanest part of the story:

TS Server Vue Language Server Total
v1 without Takeover Mode 516 MB 541 MB + 197 MB 1254 MB
v1 with Takeover Mode 541 MB + 197 MB 738 MB
v2 with Hybrid Mode 516 MB 123 MB 639 MB

(Measured on elk-zone/elk.)

The 2.0.0 that shipped broken

We thought we were ready.

Being the first language tool to go all-in on TS plugins meant being the first to hit a long list of compatibility issues our internal testing hadn't surfaced. One bug traced back to the Node.js version bundled with VSCode itself — which meant we couldn't fix it on our end. We had to wait a month for VSCode to ship an update.

I worked through every stability issue I could reproduce. User complaints kept coming for months.

By the time I'm writing this, we're on 2.0.26. Performance is meaningfully better than v1; memory usage is slightly lower than v1 Takeover Mode, without the configuration friction. The experience we set out to build is the experience users get now.

What it cost

No prior open-source project had integrated with the TS Server at this depth. Every decision had to be made from first principles. Seven months of it, August 2023 to March 2024.

More frameworks are migrating to TS plugin integration through Volar.js now — the direction was right.

Full-time open source only stays sustainable if it's funded. If Vue Language Tools is part of your team's workflow, please consider sponsoring this work.

Thanks

This post only covered Hybrid Mode. 2.0 included a lot of other work — the vue-tsc rewrite drastically reduced memory usage, among other things — which I'll write about separately.

Huge thanks to StackBlitz, who have supported my full-time development since early 2023.

Huge thanks to Astro and JetBrains for ten thousand dollars in donations that let me focus entirely on shipping this.

And to everyone else listed below — you made the difference.

Special Sponsor

Stay in the flow with instant dev experiences.
No more hours stashing/pulling/installing locally

— just click, and start coding.

Platinum Sponsors

An approachable, performant and versatile framework for building web user interfaces.

Astro powers the world's fastest websites, client-side web apps, dynamic API endpoints, and everything in-between.

Essential tools for software developers and teams.

Open Source enables Microsoft products and services to bring choice, technology and community to our customers.

Silver Sponsors
@lzm0x219
Copy link
Copy Markdown

❤️

@RayGuo-ergou
Copy link
Copy Markdown

Thanks for everything you have done! You made many people including me's life much easier!💚

@NaoyaMiyagawa
Copy link
Copy Markdown

Truly amazing work, Johnson💚 We cannot thank you enough!! Please take a break anytime you need too..!

@LouisHaftmann
Copy link
Copy Markdown

❤️

@Hyphon
Copy link
Copy Markdown

Hyphon commented Jul 15, 2024

❤️ thx for amazing work !

@jhxxs
Copy link
Copy Markdown

jhxxs commented Jul 15, 2024

❤️

@orta
Copy link
Copy Markdown

orta commented Jul 15, 2024

👍

@DrJume
Copy link
Copy Markdown

DrJume commented Jul 15, 2024

💚

@childrentime
Copy link
Copy Markdown

👍

@misbahansori
Copy link
Copy Markdown

👍

@StevenJPx2
Copy link
Copy Markdown

Thank you for the amazing work on Volar 2. Like you mentioned, the beginning phase of the v2 rollout was very rough, especially for neovim users. Now, with a little extra TLC compared to other LSPs, it works extremely well! I love the DX, especially the the scoped styles showing up in suggestions as you type in the class attribute. Don't know if that's a new feature or not.

@bruce-ws
Copy link
Copy Markdown

❤🌹

@yankeeinlondon
Copy link
Copy Markdown

Thank you for your open and very complete story of how we got to this point. Also congratulations on being a pioneer and taking the Volar plugin to a much better place by pushing into the "cutting/bleeding" edge. While the bleeding edge can be exhilarating at times it can quickly lead to disappointment and when that sits on top of many other developers expectations I can imagine that must be quite a large mental challenge. Anyway, I appreciate your openness on how hard it was and I hope you find a fast path back to recovery. We are all indebted to your work. Thanks!

@gkTim
Copy link
Copy Markdown

gkTim commented Jul 23, 2024

Thank you for all the effort and passion that you and the other developers put into this awesome tool and the vue/frontend ecosystem itself! ❤️

Sometimes it can be hard to get things working as expected and it can be exhausting, but if you get it working its one of the best feeling out there. Thats one reason that make it so much fun to be a developer and push your limits every day and be a better version of you tomorrow then you was today.

@Coastis
Copy link
Copy Markdown

Coastis commented Jul 23, 2024

❤️

@xibman
Copy link
Copy Markdown

xibman commented Jul 23, 2024

👍

@kkarasek
Copy link
Copy Markdown

Thanks and good luck 💪

@Aietes
Copy link
Copy Markdown

Aietes commented Jul 24, 2024

Thank you for all your hard work and dedication! I'm very happy with the new experience on neovim right now, great job all things considered! Don't let any negativity pull you down, keep going! ❤️

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment