vue-why-render 0.8: граф реактивности, WASM-ядро и VS Code расширение

Месяц назад я написал статью о том, как сделал отладчик рендеров для Vue — инструмент, который называет точную причину каждой перерисовки. Рассказывал про renderTriggered, про ловушки с process.env.NODE_ENV, кириллицей в байтовых смещениях и вычислением чужих computed.
С тех пор вышла версия 0.8 — с тремя большими фичами, которые я не планировал делать так быстро. Расскажу, что нового и зачем.
Что было
Если не читали первую статью — вкратце. vue-why-render подключается к Vue 3 приложению двумя строками:
import { scan } from 'vue-why-render'
scan(app, { panel: true })И показывает на каждом перерисованном компоненте: имя, счётчик рендеров, длительность и причину. Не target: Proxy, а prop badge: {text} → {text} — new reference, same value. Для Pinia — store cart.items: Array(1) → Array(0) · action clear(). Для роутера — route.params.id: "1" → "2".
Плюс панель с пятью вкладками, бюджеты рендеров, тесты (expectRenders(Card).toBe(0)), отчёты в JSON/Markdown. Ноль зависимостей, MIT.
Что нового в 0.8
1. Граф реактивности (Deps)
Раньше vue-why-render отвечал на вопрос «почему этот компонент перерисовался?». Теперь он отвечает на вопрос «кто от чего зависит?».
Новая вкладка Deps строит живую карту зависимостей: компонент ↔ реактивный источник. Здесь я как раз подключил renderTracked — в первой статье я объяснял, почему не стал его использовать (слишком много вызовов, замедляет приложение). Решение: собирать данные лениво, только для открытой вкладки Deps, и дедуплицировать на лету.
Два режима:
Components → какие ref, prop, store и computed читает этот компонент?
Sources → какие компоненты зависят от этого ref?
На каждом ребре — счётчик чтений и триггеров. Если UserAvatar читает user.name 47 раз, но это вызвало 2 рендера — остальные чтения безвредны. Если CartBadge дёргается от cart.items на каждый keystroke — вот проблема.
Это рентген для реактивности Vue.
2. Rust/WASM ядро
В первой статье всё работало на чистом JS. Для небольших приложений — нормально. Но когда компонентов сотни или тысячи, три операции начинают заметно тормозить:
Построение дерева компонентов
Дедупликация причин рендера
Сравнение (дифф) двух отчётов
Я переписал их на Rust и скомпилировал в WebAssembly.
Как это устроено:
WASM-модуль подгружается лениво, отдельным чанком. Бандл приложения не растёт — пока vue-why-render не нужен, ничего лишнего не грузится. Если WASM недоступен (SSR, jsdom, строгий CSP) — автоматически включается JS-фолбэк. Конфигурировать ничего не нужно.
scan(app, { panel: true })
// Внутри:
// 1. Пробуем загрузить .wasm чанк
// 2. Если ok — используем Rust-реализацию
// 3. Если нет — переключаемся на JS
// Потребитель не замечает разницыДля обычного приложения разница в скорости незаметна. Для крупного — заметна.
3. VS Code расширение
Браузерные DevTools — это хорошо, но переключаться между Chrome и VS Code надоело. Поэтому я сделал WebSocket-мост: сканер в браузере стримит данные прямо в редактор.
Что появляется в VS Code:
Дерево компонентов в сайдбаре — отсортировано по рендерам, иконки 🔥 для горячих компонентов
Дерево зависимостей — тот же граф реактивности
CodeLens на
.vueфайлах — количество рендеров и средняя длительность прямо над<script setup>Статус-бар — живой счётчик рендеров
Команды — pause, resume, reset из палитры
Не нужно переключаться между браузером и редактором. Данные там, где пишется код.
Что ещё добавилось
Vue DevTools интеграция — помимо собственной панели, vue-why-render теперь регистрируется в Vue DevTools. Второй инспектор с деревом реактивных источников (цветные теги: ref, prop, store, computed) и второй слой на таймлайне, логирующий каждый триггер как событие.
Nuxt модуль — одна строка в конфиге:
export default defineNuxtConfig({
modules: ['vue-why-render/nuxt']
})Модуль уже в каталоге nuxt.com/modules.
Итого
За месяц пакет набрал 668 загрузок на npm, попал в каталог модулей Nuxt, и получил три фичи, которые я честно не планировал делать в ближайшие полгода.
npm i vue-why-renderДля Nuxt:
modules: ['vue-why-render/nuxt']Ноль зависимостей. MIT. Vue 3.3+.
Если нашли баг или хотите фичу — issues открыты.
Хабы: JavaScript, Vue.js, Rust, WebAssembly, Разработка веб-сайтов Сложность: Средняя
KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.