Vue 3.6 brings Vapor mode. You add one word to a component:
<script setup vapor> and Vue compiles it to code that updates the DOM directly, with no virtual DOM. Faster updates, smaller bundle. Sounds great.
But not every feature and not every library works in a Vapor component yet. And the worst failures make no sound. The build passes. The console is empty. A button stops opening its dialog, and you find out in production.
A real example
Take a shadcn-vue dialog. Under the hood it uses as-child from Reka UI. With Vue 3.6.0-rc.14 and older, as-child inside a Vapor component does not pass attributes or listeners to the child. The button renders fine. It just has no click listener.
It's fixed in Vue 3.6.0-rc.15 now. But that one bug says a lot. If this one gives no sign at all, how many others are out there? And how do you find them before your users do?
Clicking through every page after each change is not a plan. So I built a tool for it.
Meet vaporfit
vaporfit reads your Vue project and tells you which components are safe to convert to Vapor, which are not, and why. You run it before you change a single line.
npx vaporfit Here is one finding from a small shadcn-vue test project:
error silent vf_30bf4dc5fc as-child does not pass attributes or listeners to the child in a Vapor component. Vue 3.6.0-rc.15 fixes this. src/pages/Home.vue:8:10 reka-ui/as-child chain src/pages/Home.vue > src/components/ui/dialog/Dialog.vue > reka-ui package reka-ui 2.11.0 You get the file and line, the rule, and the Vue version that fixes it. The silent part means this one fails with no error. Those are the ones I care about most.
The chain line is my favorite part. The real cause was two wrappers away from the page, inside a library. vaporfit follows the imports and shows the whole path, so you don't have to dig.
Two answers for each component
There are two ways to use Vapor today:
- Interop: you keep
createApp()and installvaporInteropPlugin. Vapor and normal components live together. This is how you migrate one component at a time. - Pure: you use
createVaporApp()and drop the virtual DOM runtime. Every component in the tree must be Vapor.
A component can be fine for one and broken for the other, so vaporfit gives each component a verdict for both: ready, blocked or unknown.
A report you can click through
If you prefer a browser to a terminal, run:
npx vaporfit ui It opens a local page with the same report. The summary shows how much of your app is ready and what holds back the most components.
The components list puts the blocked ones first, and you can filter by verdict or rule.
Click a component and you see every finding, grouped by rule, with the chain to the cause.
It also watches your files and refreshes as you edit. It runs on your machine and doesn't ask you to log in.
It knows your libraries
Most of the trouble is not in your code. It's in the libraries you use. vaporfit ships with data for 25 Vue libraries, including Reka UI, Element Plus, PrimeVue, Vuetify, Pinia, vue-i18n and VueUse.
I didn't want this data to be guesses. Each row comes from one of three things: a probe that runs in a real browser, a statement from the maintainers, or a link to an issue. The repo has 37 of those probes right now.
And when the data can't prove a problem, vaporfit says unknown. It never says ready just because it found nothing to complain about.
Let it do the boring part
Once you know what's safe, you don't have to edit each file by hand.
npx vaporfit fix # show what would change npx vaporfit fix --write # write it fix --write adds vapor only to components that are ready, and only when your app already installs vaporInteropPlugin. Blocked and unknown components stay as they are.
There are two more helpers. --router swaps $route and $router for useRoute() and useRouter(). --i18n swaps $t and friends for useI18n().
Put it in CI
You can add vaporfit to CI before you even start the migration. By default, the run fails only when a component that already has vapor is blocked. So nobody can add vapor to a component that will break, and the rest of the app doesn't block your pipeline.
Want it stricter? Add --strict and every blocked component fails the run.
What it does not do
I want to be honest here. vaporfit reads your code. It does not run your app or test behavior. "ready" means it found no known problem, not that your component is bug-free. Nuxt projects can get interop verdicts, but never a pure ready.
Vapor is still young and new problems will show up. When they do, they go into the data, with a probe or a link.
Try it
npx vaporfit You need Node.js 22.18 or later. It's MIT licensed.
If you run it on your project and it gets something wrong, or misses a library you use, please open an issue. That data is what makes the tool useful, and I can't test every library alone.
And if you've already hit a silent Vapor bug of your own, I'd love to hear about it in the comments.



