[Medium] Статический хойстинг Vue3
1. Что такое Static Hoisting в Vue 3?
Объясните static hoisting в Vue 3.
В Vue 3 static hoisting (статический хойстинг) — это оптимизация на этапе компиляции.
Определение
Во время компиляции шаблона Vue анализирует, какие узлы полностью статические (без реактивных зависимостей). Эти статичес кие узлы выносятся в константы на уровне модуля и создаются однократно. При последующих перерисовках Vue переиспользует их вместо повторного создания и сравнения.
Как это работает
Компилятор анализирует AST шаблона и выносит поддеревья, которые никогда не изменяются. При обновлениях пересоздаются только динамические части.
Пример до/после
Шаблон до компиляции:
<template>
<div>
<h1>Статический заголовок</h1>
<p>Статическое содержимое</p>
<div>{{ dynamicContent }}</div>
</div>
</template>
Скомпилированный JavaScript (упрощённо):
// статические узлы вынесены однократно
const _hoisted_1 = /*#__PURE__*/ h('h1', null, 'Статический заголовок');
const _hoisted_2 = /*#__PURE__*/ h('p', null, 'Статическое содержимое');
function render() {
return h('div', null, [
_hoisted_1, // переиспользуется
_hoisted_2, // переиспользуется
h('div', null, dynamicContent.value), // динамический
]);
}
Преимущества
- Снижение стоимости создания VNode
- Меньше работы при diff
- Лучшая производительность рендеринга
- Автоматическая оптимизация (дополнительный код не требуется)
2. Как работает Static Hoisting
Как static hoisting работает внутри?
Процесс компиляции
- Обнаружение динамических привязок
{{ }},v-bind,v-if,v-for, динамические props и т.д.
- Пометка статических узлов
- Если узел и его дочерние элементы статические -> кандидат для выноса
- Вынос статических узлов
- Перемещение статических узлов/констант за пределы
render()
- Перемещение статических узлов/констант за пределы
Пример 1: полностью статическое поддерево
<template>
<div>
<h1>Заголовок</h1>
<p>Это статический текст</p>
<div>Статический блок</div>
</div>
</template>
Скомпилировано (упрощённо):
const _hoisted_1 = h('h1', null, 'Заголовок');
const _hoisted_2 = h('p', null, 'Это статический текст');
const _hoisted_3 = h('div', null, 'Статический блок');
function render() {
return h('div', null, [_hoisted_1, _hoisted_2, _hoisted_3]);
}
Пример 2: смешанные статические и динамические элементы
<template>
<div>
<h1>Статический заголовок</h1>
<p>{{ message }}</p>
<div class="static-class">Статическое содержимое</div>
<span :class="dynamicClass">Динамическое содержимое</span>
</div>
</template>
Скомпилировано (упрощённо):
const _hoisted_1 = h('h1', null, 'Статический заголовок');
const _hoisted_2 = { class: 'static-class' };
const _hoisted_3 = h('div', _hoisted_2, 'Статическое содержимое');
function render() {
return h('div', null, [
_hoisted_1,
h('p', null, message.value),
_hoisted_3,
h('span', { class: dynamicClass.value }, 'Динамическое содержимое'),
]);
}
Пример 3: вынос статических props
<template>
<div>
<div class="container" id="main">Содержимое</div>
<button disabled>Кнопка</button>
</div>
</template>
Скомпилировано (упрощённо):
const _hoisted_1 = { class: 'container', id: 'main' };
const _hoisted_2 = { disabled: true };
const _hoisted_3 = h('div', _hoisted_1, 'Содержимое');
const _hoisted_4 = h('button', _hoisted_2, 'Кнопка');
3. Директива v-once
Директива
v-once
Если разработчик хочет явно пометить поддерево как однократно рендерящееся, используйте v-once.
Что делает v-once
v-once указывает Vue отрендерить элемент/поддерево один раз.
Даже если выражения динамические, они вычисляются только при первом рендере и больше никогда не обновляются.
Базовое использование
<template>
<div>
<!-- рендерится один раз -->
<div v-once>
<h1>{{ title }}</h1>
<p>{{ content }}</p>
</div>
<!-- обычная реактивная область -->
<div>
<h1>{{ title }}</h1>
<p>{{ content }}</p>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue';
const title = ref('Начальный заголовок');
const content = ref('Начальное содержимое');
setTimeout(() => {
title.value = 'Новый заголовок';
content.value = 'Новое содержимое';
}, 1000);
</script>
v-once vs static hoisting
| Характеристика | Static Hoisting | v-once |
|---|---|---|
| Срабатывание | Автоматический анализ компилятора | Ручная директива |
| Лучше для | Полностью статических узлов | Динамических выражений, которые должны рендериться один раз |
| Производительность | Лучше для статических секций | Хорошо для однократного динамического рендера |
| Момент принятия решения | Этап компиляции | Намерение разработчика |