Vue
Vapor Mode: рендеринг без virtual DOM
Классический Vue при изменении состояния строит новое виртуальное дерево, сравнивает его со старым и применяет разницу к настоящему DOM. Это надёжно, но сам diff стоит процессорного времени и памяти на каждый рендер. Vue 3.6 предлагает Vapor Mode: компилятор анализирует шаблон на этапе сборки и генерирует код, который при изменении реактивного значения трогает ровно тот узел DOM, что зависит от него. Никакого virtual DOM в рантайме, производительность ближе к SolidJS, включается по одному компоненту.
- Таблица на десятки тысяч строк: точечное обновление ячейки вместо diff всего дерева на каждое изменение
- Дашборд реального времени: метрики обновляются каждую секунду, Vapor убирает накладные расходы diff
- Встраиваемый виджет: меньший рантайм и быстрый старт там, где важен вес и отзывчивость
- Редактор с тысячами реактивных полей: прямые операции с DOM вместо пересборки виртуального дерева
- Гибридное приложение: тяжёлый список в Vapor-компоненте, остальной UI на классических компонентах
Предварительные знания
- Глубокая реактивность Vue: как ref и зависимости отслеживают изменения
- Идея virtual DOM и reconciliation из ранних уроков
- Понимание разницы между этапом компиляции и рантаймом
Стоимость virtual DOM
В классическом Vue компонент при каждом рендере возвращает описание UI, виртуальное дерево лёгких объектов. Vue сравнивает его с предыдущим деревом (reconciliation) и применяет к настоящему DOM только разницу. Подход устойчив и предсказуем, но сам diff и создание виртуальных узлов стоят CPU и памяти, и эта цена платится при каждом обновлении, даже если изменилось одно значение.
На небольшом UI цена diff незаметна, и virtual DOM остаётся отличным выбором. Она становится ощутимой на больших, часто обновляемых деревьях: таблицы на десятки тысяч строк, дашборды реального времени, редакторы с множеством реактивных полей.
Ключевая идея: diff делает работу пропорционально размеру дерева, а не размеру изменения. Изменили одну ячейку, а сравнить пришлось значительную часть структуры. Именно эту пропорциональность Vapor Mode стремится убрать.
В чём состоит цена virtual DOM в классическом Vue при обновлении?
Как Vapor компилирует шаблон
Vapor Mode переносит работу с рантайма на этап компиляции. Компилятор анализирует шаблон SFC и видит, какие узлы DOM зависят от каких реактивных значений. Он генерирует код, который создаёт настоящие DOM-узлы один раз, а при изменении значения обновляет точечно только связанный узел. Виртуального дерева и diff в рантайме нет вовсе.
- Классический рендер — Рантайм строит виртуальное дерево, делает diff, применяет разницу. Работа пропорциональна размеру дерева на каждое изменение
- Vapor рендер — Компилятор заранее связал узлы с реактивными значениями. При изменении трогается ровно зависимый узел. Работа пропорциональна размеру изменения
Этот подход называют fine-grained реактивностью: обновление адресует конкретный узел, а не перерисовывает компонент. Та же модель лежит в основе SolidJS, и Vapor Mode приносит её в Vue, сохраняя привычный синтаксис SFC.
Что Vapor Mode делает на этапе компиляции, чего нет в классическом подходе?
Производительность и гибридное использование
Без virtual DOM Vapor-компонент несёт меньше рантайма и обновляется дешевле. Выигрыш растёт с объёмом данных и частотой обновлений: на таблице в десятки тысяч строк или дашборде, который тикает каждую секунду, экономия diff заметна. На небольшом статичном UI разница невелика, и классический режим там вполне хорош.
| Сценарий | Классический | Vapor |
|---|---|---|
| Маленький статичный UI | Отлично | Разница незаметна |
| Таблица на 50k строк | Diff дорогой | Точечное обновление |
| Дашборд реального времени | Накладные расходы | Меньший рантайм |
| Встраиваемый виджет | Полный рантайм | Лёгкий рантайм |
Vapor включается по одному компоненту, а не для всего приложения сразу. Vapor-компоненты и классические сосуществуют в одном дереве, поэтому миграция инкрементальная: тяжёлый список переводят в Vapor, остальной UI остаётся как есть. Это снижает риск и не требует переписывать приложение целиком.
Vapor это не замена классическому Vue, а второй режим под другой профиль нагрузки. Решение принимают по данным профайлера: если diff не узкое место, переход на Vapor не даст заметного выигрыша и лишь добавит экспериментальный код.
Как Vapor Mode сочетается с классическими компонентами в одном приложении?
Экспериментальный статус в 2026
В 2026 году Vapor Mode остаётся экспериментальным. Не все возможности Vue поддерживаются в Vapor-компонентах одинаково, часть библиотек экосистемы рассчитана на virtual DOM и может работать иначе или не работать, а API и поведение могут измениться между версиями. Это накладывает ограничения на использование в проде.
Экспериментальный статус означает, что Vapor не ставят на критичный путь без запасного плана. Его обкладывают тестами, ограничивают изолированными тяжёлыми компонентами и следят за заметками к релизам Vue, чтобы вовремя поймать изменения API.
Разумная тактика: применять Vapor точечно там, где профайлер показал, что diff это узкое место, и где совместимость с используемыми библиотеками проверена. Для остального UI классический режим в 2026 году остаётся стабильным дефолтом.
Перед внедрением Vapor проверяют две вещи: подтверждает ли профайлер выигрыш на конкретном компоненте и совместимы ли нужные библиотеки. Без обеих галочек переход добавляет риск без гарантированной пользы.
Что означает экспериментальный статус Vapor Mode для использования в 2026 году?
Связь с другими темами
Урок про рычаг производительности на уровне рендеринга. Рядом стоят разбиение бандла и SSR:
- Асинхронные компоненты и code-splitting — Другой рычаг: снижение веса бандла, тогда как Vapor снижает стоимость рендеринга
- SSR и Nuxt 4 — Режим рендеринга влияет на серверный рендер и гидратацию
Итог
- Классический Vue использует virtual DOM: новое дерево, diff со старым, применение разницы к настоящему DOM на каждый рендер
- Vapor Mode компилирует SFC в код, который при изменении реактивного значения трогает ровно зависимый узел DOM, без virtual DOM
- Это даёт производительность уровня fine-grained реактивности SolidJS и меньший рантайм, особенно на больших объёмах данных
- Vapor включается по компоненту через <script setup vapor>, а классические и Vapor-компоненты сочетаются в одном приложении
- В 2026 году Vapor Mode всё ещё экспериментальный: не все возможности и библиотеки поддерживаются, API может меняться
Связанные уроки
- vue-33-async-components — Code-splitting режет вес бандла, Vapor режет стоимость рендеринга. Оба про производительность, но на разных уровнях
- vue-36-ssr-nuxt — Vapor влияет и на серверный рендеринг с гидратацией, что напрямую касается SSR и Nuxt