Продуктивність Vue 3 у 2026: Vapor Mode, Alien Signals і кінець Virtual DOM
Детальний розбір продуктивності Vapor Mode у Vue 3.6: як він усуває Virtual DOM, система реактивності Alien Signals, бенчмарки проти Solid.js та практичні техніки оптимізації для продакшн-застосунків.

Vue 3.6 Vapor Mode — це найзначніша зміна архітектури рендерингу відтоді, як Vue запровадило Virtual DOM у версії 2. Компілюючи Single File Component безпосередньо в імперативні операції з DOM, Vapor Mode усуває накладні витрати на diffing, які роками визначали конвеєр рендерингу Vue. У поєднанні з переписаною на основі Alien Signals системою реактивності Vue 3.6 досягає в бенчмарках паритету з Solid.js і Svelte 5 — без потреби вивчати розробникам новий API.
Vapor Mode — це опціональна стратегія компіляції у Vue 3.6, яка повністю обходить Virtual DOM. Компоненти, скомпільовані у Vapor Mode, прив'язують кожну реактивну залежність безпосередньо до точного вузла DOM, на який вона впливає, створюючи хірургічно точні оновлення без жодного обходу дерева. Вмикається це одним атрибутом: <script setup vapor>.
Як працює Virtual DOM у Vue — і чому він став вузьким місцем
Патерн Virtual DOM (VDOM), популяризований React і запозичений Vue 2, створює легке JavaScript-представлення реального дерева DOM. За кожної зміни стану Vue генерує нове дерево VDOM, порівнює його з попереднім і застосовує зміни лише до змінених вузлів реального DOM.
Цей підхід добре працює для більшості застосунків. Алгоритм diffing виконується за час O(n), а компілятор Vue вже оптимізує статичні піддерева, виключаючи їх зі шляху diffing. Але накладні витрати накопичуються в певних сценаріях:
- Великі списки із сотнями рядків запускають повні порівняння піддерев за кожного оновлення
- Часті зміни стану (анімації, дані в реальному часі) створюють VDOM churn, який має прибирати збирач сміття
- Глибокі дерева компонентів примножують вартість обходу дерева та генерації змін
Компілятор шаблонів Vue 3 запровадив кілька оптимізацій VDOM — static hoisting, patch flags, block trees, — які зменшили зайву роботу. Вони дали відчутні покращення, але базова архітектура все одно вимагала генерувати, порівнювати та відкидати JavaScript-об'єкти за кожного циклу рендерингу.
Vue 3.6 Vapor Mode: компіляція, що усуває Virtual DOM
Vapor Mode застосовує цілком інший підхід. Замість компілювати шаблони у функції рендерингу, що повертають вузли VDOM, компілятор Vapor генерує код, який безпосередньо створює й оновлює елементи DOM. Кожна реактивна прив'язка відповідає конкретній мутації DOM — проміжне представлення не потрібне.
Ось як стандартний компонент Vue компілюється по-різному в кожному з режимів:
<!-- Counter.vue -->
<script setup vapor>
import { ref } from 'vue'
const count = ref(0)
const increment = () => count.value++
</script>
<template>
<button @click="increment">
Count: {{ count }}
</button>
</template>У класичному режимі VDOM цей шаблон компілюється у функцію рендерингу, що повертає дерево віртуальних вузлів. За кожного кліку Vue створює нове дерево VDOM, порівнює його з попереднім, виявляє зміну текстового вмісту й застосовує зміну до реального DOM.
У Vapor Mode компілятор генерує щось ближче до цього:
// Simplified Vapor compilation output
const button = document.createElement('button')
const text = document.createTextNode('Count: 0')
button.appendChild(text)
// Direct binding: reactive source -> DOM mutation
effect(() => {
text.nodeValue = `Count: ${count.value}`
})
button.addEventListener('click', increment)Реактивний ефект прив'язує count безпосередньо до text.nodeValue. Жодного створення VDOM, жодного diffing, жодного застосування змін. Зміна стану запускає рівно одну мутацію DOM.
Увімкнення Vapor Mode у проєкті
Vapor Mode працює на рівні компонента. Існують дві стратегії інтеграції:
import { createVaporApp } from 'vue'
import App from './App.vue'
createVaporApp(App).mount('#app')import { createApp, vaporInteropPlugin } from 'vue'
import App from './App.vue'
createApp(App)
.use(vaporInteropPlugin)
.mount('#app')Гібридний підхід дозволяє поступову міграцію. Критичні до продуктивності компоненти — таблиці даних, панелі в реальному часі, насичені анімацією подання — можуть перейти на Vapor, тоді як решта застосунку й далі використовує стандартне середовище виконання VDOM. Обидва типи компонентів співіснують в одному дереві компонентів.
Vapor Mode потребує Composition API з <script setup>. Options API, app.config.globalProperties, getCurrentInstance() та події життєвого циклу на рівні елемента (@vue:mounted тощо) не підтримуються. Користувацькі директиви використовують інший інтерфейс, який приймає реактивні гетери замість об'єктів прив'язки. Suspense працює, коли компоненти Vapor обгорнуті в батьківський VDOM, але не в суто Vapor-застосунках.
Alien Signals: новий рушій реактивності Vue
Vue 3.6 поряд із Vapor Mode приносить другу велику зміну: повне переписання @vue/reactivity на основі бібліотеки Alien Signals. Створена Джонсоном Чу, Alien Signals реалізує алгоритм реактивності push-pull, який зменшує як виділення пам'яті, так і обчислювальні накладні витрати.
Модель push-pull працює у дві фази:
- Фаза push — Коли сигнал (реактивне джерело) змінюється, він поширює прапорець «dirty» на всі залежні computed-властивості. Цей обхід дешевий: він лише перемикає булеві прапорці, не виконуючи жодних обчислень.
- Фаза pull — Коли computed-властивість зчитується, вона перевіряє свій прапорець dirty. Якщо вона dirty, то переобчислюється. Якщо clean, то одразу повертає кешоване значення.
Цей дизайн усуває зайві переобчислення. У системі реактивності Vue 3.5 computed-властивість, що залежить від трьох сигналів, переобчислювалася за зміни будь-якого сигналу, навіть якщо результат залишався тим самим. Alien Signals переобчислює лише тоді, коли значення фактично зчитується й змінилася принаймні одна залежність.
import { ref, computed, watch } from 'vue'
const firstName = ref('Jane')
const lastName = ref('Doe')
const isActive = ref(true)
// This computed only recalculates when read AND dirty
const displayName = computed(() => {
return isActive.value
? `${firstName.value} ${lastName.value}`
: 'Inactive User'
})
// Changing isActive marks displayName as dirty
// But no computation runs until something reads displayName.value
isActive.value = false
// NOW the recalculation happens
console.log(displayName.value) // 'Inactive User'Внутрішня структура даних також змінилася. Alien Signals замінює відстеження залежностей на основі Set двозв'язними списками, що зменшує пам'ять на кожну реактивну залежність і пришвидшує обхід під час очищення.
Результати бенчмарків: Alien Signals на практиці
Цифри з бенчмарків бети Vue 3.6 показують послідовні покращення порівняно з Vue 3.5:
| Метрика | Vue 3.5 | Vue 3.6 (Alien Signals) | Покращення | |---|---|---|---| | Пам'ять на реактивний ref | Базовий рівень | -14% | Менше виділення | | Переобчислення computed | Базовий рівень | -20% у сер. | Менше зайвих запусків | | Монтування компонентів (100k) | ~300ms | ~100ms | у 3 рази швидше | | First Contentful Paint | Базовий рівень | типово 0,7s | Менші накладні витрати фреймворку | | Базовий розмір бандла | ~16KB | <10KB | -37% |
Ці здобутки застосовуються автоматично до всіх застосунків Vue 3.6. На відміну від Vapor Mode, який вимагає вмикання покомпонентно, система реактивності Alien Signals є типовою у Vue 3.6.
Готовий до співбесід з Vue.js / Nuxt.js?
Практикуйся з нашими інтерактивними симуляторами, flashcards та технічними тестами.
Практичні техніки оптимізації продуктивності Vue 3
Vapor Mode та Alien Signals розв'язують накладні витрати на рівні фреймворку, але продуктивність на рівні застосунку все одно залежить від того, як структуровані компоненти. Ці техніки застосовні як до компонентів VDOM, так і до Vapor.
Поверхнева реактивність для великих структур даних
Глибока реактивність обгортає кожну вкладену властивість у Proxy. Для великих наборів даних — відповідей API, об'єктів конфігурації, кешованого стану — це створює тисячі зайвих обгорток Proxy. shallowRef і shallowReactive обмежують реактивність посиланням верхнього рівня.
import { shallowRef, triggerRef } from 'vue'
interface Product {
id: number
name: string
variants: { sku: string; price: number }[]
}
// Only the ref itself is reactive, not the nested properties
const products = shallowRef<Product[]>([])
// Fetching data — assign the new array to trigger reactivity
async function fetchProducts() {
const response = await fetch('/api/products')
products.value = await response.json() // triggers update
}
// Mutating nested data — must manually trigger
function updatePrice(productId: number, sku: string, newPrice: number) {
const product = products.value.find(p => p.id === productId)
const variant = product?.variants.find(v => v.sku === sku)
if (variant) {
variant.price = newPrice
triggerRef(products) // explicit trigger required
}
}Директива v-memo для дорогого рендерингу списків
Для компонентів VDOM, що рендерять довгі списки, v-memo кешує результати рендерингу піддерев на основі значень залежностей. VDOM повністю пропускає diffing для мемоїзованих піддерев, залежності яких не змінилися.
<!-- ProductGrid.vue -->
<script setup>
import { ref } from 'vue'
const products = ref([])
const selectedId = ref(null)
</script>
<template>
<div class="grid">
<div
v-for="product in products"
:key="product.id"
v-memo="[product.id === selectedId, product.price]"
:class="{ selected: product.id === selectedId }"
>
<h3>{{ product.name }}</h3>
<span>{{ product.price }}</span>
</div>
</div>
</template>Масив v-memo [product.id === selectedId, product.price] каже Vue: не рендерити цей елемент повторно, доки не зміниться стан вибору або ціна. Для списку з 500 продуктів, де вибирається лише один, це зменшує роботу VDOM із 500 diff піддерев до 2 (попередньо вибраний і щойно вибраний елементи).
Асинхронні компоненти з Suspense для розділення коду
Лінива загрузка важких компонентів утримує початковий бандл компактним. defineAsyncComponent від Vue у поєднанні з Suspense декларативно обробляє стан завантаження.
<!-- Dashboard.vue -->
<script setup>
import { defineAsyncComponent } from 'vue'
// Heavy charting library loaded only when needed
const AnalyticsChart = defineAsyncComponent(() =>
import('./components/AnalyticsChart.vue')
)
const DataExport = defineAsyncComponent({
loader: () => import('./components/DataExport.vue'),
delay: 200, // show loading after 200ms
timeout: 10000, // fail after 10s
})
</script>
<template>
<Suspense>
<template #default>
<AnalyticsChart />
<DataExport />
</template>
<template #fallback>
<div class="skeleton-loader" />
</template>
</Suspense>
</template>Vapor Mode проти VDOM: коли який підхід використовувати
Vapor Mode не є універсальною заміною Virtual DOM. Кожен режим компіляції має сильні сторони, що пасують різним профілям компонентів.
| Сценарій | Рекомендований режим | Причина | |---|---|---| | Таблиці даних (1000+ рядків) | Vapor | Усуває накладні витрати VDOM на рядок | | Панелі в реальному часі | Vapor | Часті оновлення виграють від прямої прив'язки до DOM | | Компоненти, насичені анімацією | Vapor | Немає тиску на GC через VDOM churn | | Сторонні бібліотеки компонентів VDOM | VDOM | Шар взаємодії додає складності | | Компоненти, що використовують Options API | VDOM | Vapor потребує Composition API | | Форми зі складною валідацією | Будь-який | Мінімальні накладні витрати рендерингу в обох режимах | | Сторінки зі статичним вмістом | Будь-який | Основну роботу виконує SSG/SSR |
Рекомендований шлях міграції: спочатку профілюйте застосунок за допомогою вкладки Performance у Vue DevTools. Визначте компоненти з найвищим часом рендерингу та частотою повторного рендерингу. Перетворіть їх на Vapor Mode, виміряйте вплив і розширюйте далі.
Питання для співбесід: продуктивність Vue 3 і Vapor Mode
Ці питання відображають те, про що інженерні команди запитують у 2026 році, оцінюючи експертизу у Vue. Кожна відповідь узагальнює технічну логіку, яку очікує інтерв'юер.
П: Яку проблему розв'язує Vapor Mode і чим він відрізняється від оптимізацій VDOM, які Vue вже мало?
Компілятор VDOM у Vue 3 уже оптимізував статичні піддерева, додавав patch flags та реалізовував block trees, щоб пропускати зайві diff. Це зменшувало накладні витрати VDOM, але не усувало їх — кожна зміна стану все одно вимагала створювати вузли VDOM, обходити дерево та генерувати зміни. Vapor Mode прибирає весь цей конвеєр. Компілятор зіставляє реактивний стан безпосередньо з мутаціями DOM, тож зміна стану запускає рівно ті операції DOM, які потрібні, — без проміжних структур даних, без алгоритму diffing, без збирання сміття з відкинутих вузлів VDOM.
П: Чи можуть компоненти Vapor і VDOM співіснувати в одному застосунку?
Так. vaporInteropPlugin дозволяє обидва типи компонентів в одному дереві компонентів. Батьківський VDOM може рендерити дочірні Vapor і навпаки, з певними застереженнями: слоти Vapor не можуть використовувати slots.default() усередині компонента VDOM (натомість використовуйте renderSlot), а взаємодія з бібліотеками компонентів на основі VDOM (Vuetify, PrimeVue) може мати шорсткості на експериментальному етапі.
П: Поясніть модель реактивності push-pull в Alien Signals у Vue 3.6.
Модель push-pull розділяє реактивні оновлення на дві фази. У фазі push, коли сигнал змінює значення, система поширює прапорець dirty донизу через усі залежні computed-властивості — це дешево, бо лише перемикає булеві прапорці. У фазі pull, коли computed-значення фактично зчитується, воно перевіряє, чи є воно dirty. Якщо dirty, то переобчислюється зі своїх залежностей. Якщо clean, то повертає кешоване значення. Це уникає завчасного переобчислення computed-властивостей, які в певному циклі оновлення можуть так і не зчитатися.
П: Коли слід використовувати shallowRef замість ref у застосунку Vue 3?
shallowRef доречний, коли структура даних велика і лише переприсвоєння верхнього рівня має запускати реактивність — кеші відповідей API, об'єкти конфігурації та великі масиви, де мутації окремих елементів контролюються вручну за допомогою triggerRef(). Глибока реактивність обгортає кожну вкладену властивість у Proxy, що є зайвими накладними витратами для даних, які замінюватимуться цілком, а не мутуватимуться на місці.
Практикуйте більше питань для співбесід із Vue.js про composables і патерни реактивності на SharpSkill.
Офіційний посібник з продуктивності Vue.js охоплює додаткові техніки оптимізації, зокрема стабільність пропсів, віртуальний скролінг і SSR-стримінг. Примітки до випуску бети Vue 3.6 документують кожен API Vapor Mode і відоме обмеження.
Починай практикувати!
Перевір свої знання з нашими симуляторами співбесід та технічними тестами.
Висновок
- Vapor Mode компілює SFC Vue у прямі операції з DOM, повністю усуваючи створення, diffing і застосування змін Virtual DOM
- Вмикається покомпонентно за допомогою
<script setup vapor>— без міграції в масштабі всього застосунку - Alien Signals, новий типовий рушій реактивності, зменшує використання пам'яті на 14% і покращує продуктивність computed-властивостей завдяки лінивому обчисленню push-pull
- Використовуйте
shallowRefдля великих структур даних,v-memoдля дорогого рендерингу списків іdefineAsyncComponentдля розділення коду — ці патерни застосовні в обох режимах - Vapor Mode потребує Composition API з
<script setup>. Options API,getCurrentInstance()іglobalPropertiesне підтримуються - Спочатку профілюйте за допомогою Vue DevTools, перетворюйте на Vapor компоненти з найбільшим впливом, вимірюйте та ітеруйте
- Vue 3.6 перебуває в беті на початку 2026 року — ставтеся до Vapor Mode як до експериментального для продакшн-застосунків, але починайте напрацьовувати обізнаність команди вже зараз
Теги
Поділитися
Пов'язані статті

Просунуті Vue 3 Composables: патерни повторного використання та питання для співбесіди 2026
Вичерпний посібник з просунутих Vue 3 Composables: патерни повторного використання, асинхронна обробка помилок, Dependency Injection, валідація форм та актуальні питання для технічних співбесід у 2026 році.

Nuxt 4 у 2026 році: Нова структура каталогів та міграція з Nuxt 3
Повний посібник з міграції на Nuxt 4: нова структура app/, singleton-шар отримання даних, поверхнева реактивність за замовчуванням, розділення TypeScript-контексту, нормалізовані імена компонентів, Vue Router v5, зміни в управлінні head та контрольний список міграції.

Vue 3 Pinia vs Vuex: Сучасне управління станом та питання для співбесід 2026
Порівняння Pinia та Vuex: архітектура, TypeScript, Composition API, міграція, гідратація SSR та найпоширеніші питання зі співбесід щодо управління станом Vue у 2026 році.