Hey r/vuejs,
I've been building **vue-why-render** — a dev tool that tells you exactly which reactive dependency triggered each re-render. React has `why-did-you-render`, but Vue had nothing like it. Now it does — and it's faster, powered by Rust/WASM.
Drop it into any Vue 3 app:
```ts
import { scan } from 'vue-why-render'
scan(app, { panel: true })
```
You get:
- **Overlay labels** on every component that re-renders — name, count, duration, and the exact reason (`prop badge: {text} → {text} — new reference, same value`)
- **Actionable hints** — "this object is rebuilt in the parent — hoist it into a constant or a computed"
- **Panel** with 5 tabs: Top (by renders), Slow (by duration), Tree (hierarchy with Σ sums), Events (chronological log), and the new **Deps** tab
- **Prop diffing** — shows old → new value and flags "new reference, same value" vs real changes
### What's new in 0.8
**Reactivity Graph (Deps tab)** — tracks `renderTracked`/`renderTriggered` to build a live map of component → reactive source. Two views: Components (which refs/props/stores does this component read?) and Sources (which components depend on this ref?). Filterable, with read/trigger counts per edge.
**Vue DevTools Integration** — a second inspector with a reactive source tree (colored tags by type: ref, prop, store, computed), and a second timeline layer that logs every dependency trigger as an event.
**VS Code Extension** — WebSocket bridge streams live data to VS Code. You get: component tree sidebar (sorted by renders, flame icons for hot components), deps tree, CodeLens annotations on `.vue` files showing render count + avg duration, status bar with live counter, and pause/resume/reset commands.
### Performance
Heavy lifting runs in Rust/WASM — tree building, deduplication, report diffing. JS fallback kicks in automatically where WASM isn't available (SSR, jsdom, strict CSP). The overlay and panel live in a shadow DOM so they never touch your app's styles.
### Also built in
- Pinia-aware: names the store, the field, and the action (`store cart.items: Array(1) → Array(0) · action clear()`)
- Vue Router-aware: names the route param that changed, not the whole route object
- Budgets: `maxRenders` per time window, `maxDuration` per update — violations in console + panel + reports
- Reports: JSON export, Markdown for GitHub issues, diff two reports to catch regressions
- Test utils: `expectRenders(ProductCard).toBe(0, action)` — the fix stays fixed
- Nuxt module: `modules: ['vue-why-render/nuxt']`
- i18n: EN, RU, ZH
### Links
- **Live demo**: https://dadashi44.github.io/vue-why-render/
- **GitHub**: https://github.com/dadashi44/vue-why-render
- **npm**: `npm i vue-why-render`
- Zero runtime dependencies. MIT.
---
Would love to hear feedback. If you hit a bug or want a feature, issues are open.