Олег Марков
Как работает компиляция Vue Core
Введение
Vue.js – это один из популярнейших фреймворков для создания современных веб-приложений. Его основу составляет ядро (Vue Core) и система компиляции шаблонов. Понимание того, как происходит компиляция внутри Vue Core помогает разработчикам оптимизировать свои компоненты, выявлять узкие места, а также лучше разбираться в механизмах реактивности и обновлений, которые дает этот фреймворк.
В этой статье я подробно расскажу, как Vue компилирует шаблоны, превращая их в быстрый JavaScript-код, который обновляет DOM с минимальными затратами. Покажу основные этапы компиляции на примерах кода, разберу внутренние функции и архитектуру процесса. Вы поймете разницу между рантайм- и ahead-of-time-компиляцией, узнаете о структуре AST и увидите, что происходит “под капотом” при работе с вашими .vue файлами.
Как устроена система компиляции Vue
Vue Core компилирует шаблоны компонентов в render-функции на JavaScript. Еще проще — ваш HTML-привычный синтаксис становится чистым JS, который умеет максимально эффективно обновлять интерфейс.
Давайте поговорим о ключевых частях этого процесса.
Зачем вообще нужна компиляция?
Vue — декларативный фреймворк: вы описываете, как должен выглядеть интерфейс, а что происходит в браузере «под капотом» — скрыто. Компиляция шаблонов позволяет преобразовать декларативный синтаксис Vue в низкоуровневую инструкцию для реактивного движка, который быстро меняет только изменившиеся части DOM.
- Простые шаблоны проще писать и читать.
- Генерация оптимизированного кода происходит автоматически.
- Меньше ошибок — не нужно вручную писать render-функции.
Разбираться в тонкостях компиляции ядра Vue — это продвинутый навык, который позволяет лучше понимать, как работает фреймворк изнутри. Но для создания полноценных приложений, необходимо также понимать, как устроена архитектура, как управлять состоянием и как организовать маршрутизацию. Если вы хотите углубить свои знания о Vue и стать экспертом, приходите на наш большой курс Vue.js 3, Vue Router и Pinia. На курсе 173 уроков и 21 упражнение, AI-тренажеры для безлимитной практики с кодом и задачами 24/7, решение задач с живым ревью наставника, еженедельные встречи с менторами.
Два основных режима компиляции: в рантайме и на этапе сборки
Рантайм-компиляция (Runtime compilation)
В этом случае браузер получает исходный шаблон (обычно это строка внутри опции template). Прямо во время выполнения приложение берет этот шаблон и компилирует его на лету в render-функцию.
new Vue({
el: '#app',
template: '<div>{{ message }}</div>',
data: {
message: 'Hello'
}
})
// Шаблон компилируется уже в браузере
Преимущества:
- Гибкость — шаблон можно формировать динамически, например, на сервере.
Недостатки:
- Компилятор загружает вес итогового бандла на ~10-15кб.
- Производительность чуть ниже, чем у pre-compiled рендер-функции.
Компиляция во время билда (Ahead-of-Time, AOT)
Второй подход — компиляция на этапе сборки (чаще всего через webpack-плагин vue-loader или Vite). Тогда .vue шаблоны превращаются в JS render-функции ещё ДО передачи кода браузеру.
// Внутри Single File Component (.vue)
// <template>
// <div>{{ message }}</div>
// </template>
// vue-loader превратит это в функцию render.
// В prod-сборке браузер уже получает только render-функцию, никакой лишней работы на клиенте!
Преимущества:
- Максимальная производительность.
- Нет лишнего кода компилятора в вашем бандле.
- Ранние ошибки в шаблоне будет видно на этапе сборки.
Недостатки:
- Нет возможности динамически менять шаблон на клиенте.
Рекомендация: во всех production-проектах используйте AOT-компиляцию (с vue-loader, Vite, Rollup-плагином — не важно). Рантайм-компиляция нужна только для особых случаев.
Этапы компиляции в Vue Core
Давайте разберем пошагово, что происходит с вашим шаблоном до его «оживления» в браузере.
Этап 1. Парсинг: шаблон превращается в AST
Первый шаг компилятора — это парсинг шаблона и построение абстрактного синтаксического дерева (AST — Abstract Syntax Tree).
Что такое AST в Vue?
AST — это дерево JavaScript-объектов, где каждая нода — тег, атрибут, директива, текст. Компилятор не работает с текстом напрямую, а с уже разобранной структурой.
Вот так это выглядит на псевдокоде:
<div>
<h1>{{ title }}</h1>
<button @click="increment">Добавить</button>
</div>
AST для такого шаблона будет напоминать:
{
type: 'Element',
tag: 'div',
children: [
{
type: 'Element',
tag: 'h1',
children: [
{
type: 'Interpolation',
content: 'title'
}
]
},
{
type: 'Element',
tag: 'button',
props: [
{
name: 'onClick',
value: 'increment'
}
],
children: [
{
type: 'Text',
content: 'Добавить'
}
]
}
]
}
AST строится специальной функцией-парсером, которая разбирает входной HTML на узлы-структуры.
Этап 2. Трансформация дерева: работа оптимизаторов
AST можно анализировать и модифицировать. Следующим шагом Vue-компилятор применяет преобразования (трансформации):
- Распознается, какие части шаблона статичны (static content hoisting).
- Обнаруживаются циклы (
v-for) и условия (v-if,v-else). - Директивы Vue переводятся во внутренние инструкции.
В этом этапе можно оптимизировать работу рендера, чтобы избежать лишних вычислений при обновлении данных.
Пример — оптимизация статических блоков:
<div>
<span>Это всегда статично</span>
<span>{{ динамика }}</span>
</div>
В AST первый <span> можно вынести в отдельную переменную, чтобы не пересчитывать его при каждом рендере.
Этап 3. Генерация кода (Codegen)
Теперь пришло время превращать AST в финальную render-функцию. Эта функция — обычный чистый JavaScript, который создает виртуальное дерево DOM (VNode) для реактивного движка Vue.
Посмотрим на реальный пример.
Исходный шаблон
<div>
<p>{{ msg }}</p>
</div>
Итоговый JS к которому ведет компиляция (упрощенно):
function render(ctx, cache) {
return _createElementVNode(
'div',
null,
[
_createElementVNode(
'p',
null,
[
_toDisplayString(ctx.msg) // ctx — ссылка на реактивные данные
]
)
]
);
}
_createElementVNode— вспомогательная функция Vue для создания VNode-ноды._toDisplayStringпревращает переменную во что-то, что можно вставить в DOM (например, экранированную строку).
Благодаря этому, actual DOM не обновляется весь, а только те участки, что были реально изменены (msg).
Немного глубже: функции компилятора Vue
В реальной жизни при работе с Vue Core и его внутренностями вы встретите такие функции и пакеты:
@vue/compiler-dom— основной пакет для компиляции шаблонов во frontend.compile— главная функция, принимающая строку-шаблон, возвращающая render-функцию.parse— разбирает шаблон и возвращает AST.transform— преобразует AST, оптимизируя его.generate— превращает AST в JavaScript-код рендера.
Покажу порядок вызова:
import { compile } from '@vue/compiler-dom';
const { code } = compile('<div>{{ message }}</div>');
// В code теперь содержится JS render-функция в виде строки
Если хочется увидеть AST для любого шаблона, это можно сделать вручную:
import { baseParse } from '@vue/compiler-core';
const ast = baseParse('<div><p>Привет, {{ name }}</p></div>');
console.log(JSON.stringify(ast, null, 2));
// Вывод: подробное дерево элементов, текстовых узлов и интерполяций
Особенности и возможности компилятора Vue
Генерация SSR-кода
Если вы используете Vue для SSR (server-side rendering), шаблоны компилируются по-другому — AST превращается в код, который можно запустить на сервере для генерации HTML-строк.
Для этого служит пакет @vue/compiler-ssr.
Работа с директивами, слотами и v-bind
Компилятор Vue умеет разбирать и превращать любые стандартные директивы (v-if, v-for, v-show, v-bind, v-on) в быстрые JS-выражения.
Пример кода с условиями:
<div>
<span v-if="ok">Да</span>
<span v-else>Нет</span>
</div>
Компиляция превратится примерно в:
// Псевдокод рендера
function render(ctx) {
return _createElementVNode(
'div',
null,
[
ctx.ok
? _createElementVNode('span', null, 'Да')
: _createElementVNode('span', null, 'Нет')
]
)
}
Слоты, директивы, даже пользовательские компоненты — всё это превращается в JS-функции, которые умеют быстро реагировать на реактивность «снаружи».
Интересные оптимизации: patchFlag, static hoisting
Vue-компилятор генерирует специальные подсказки (patchFlags), чтобы движок понимал, как лучше обновлять виртуальное дерево DOM. Это делает работу вашего приложения быстрее даже на больших интерфейсах.
static hoisting — вынесение неизменяемых частей шаблона во внешние переменные, чтобы не пересоздавать их каждый раз.
patchFlag — специальные биты, которые указывают, какие свойства в VNode могут меняться.
Как изучать, что происходит внутри — инструменты и лайфхаки
- Воспользуйтесь онлайн-песочницей: https://template-explorer.vuejs.org/ — сюда можно вставить любой шаблон и увидеть AST, оптимизации и финальный render-код.
- Можно смотреть сгенерированный render-код для компонентов через vue-loader (ищите render.js файлы рядом с вашими .vue-компонентами после сборки).
Практический пример: end-to-end
Допустим, у вас есть такой компонент:
<template>
<ul>
<li v-for="item in list" :key="item.id">{{ item.text }}</li>
</ul>
</template>
В ходе компиляции происходят такие шаги:
- Парсинг: создается AST дерева — ul с вложенными li, где есть v-for и интерполяция.
- Трансформация: v-for луп распознается как специальная структура для itераций.
- Генерация рендер-функции:
function render(ctx, cache) {
return _createElementVNode(
"ul",
null,
_renderList(ctx.list, (item) =>
_createElementVNode("li", { key: item.id }, _toDisplayString(item.text))
)
)
}
_renderList— вспомогательная функция для циклов.- Каждый
liполучает свой уникальный ключ.
Как видите, шаблон превращается в чистый, оптимизированный JS, который максимально быстро обновляет только изменяющиеся строки или элементы списка.
Заключение
Система компиляции в Vue Core — одна из сильнейших сторон этого фреймворка. Она позволяет писать выразительные и читаемые шаблоны на близком к HTML синтаксисе, а потом превращает их в сверхбыстрые JavaScript-функции, заточенные на минимальный объем изменений DOM.
Компиляция проходит через три этапа: парсинг (в AST), трансформация (оптимизации и подсказки для движка), и генерация рендер-кода. В итоге даже самый большой Vue-проект будет работать быстро, потому что обновляет только нужные части интерфейса.
Осознанное понимание механизма компиляции дает вам возможность находить и устранять узкие места, писать более чистый и “быстрый” код, использовать дополнительные возможности оптимизации.
Понимание принципов компиляции ядра, безусловно, полезно, но без знаний архитектуры приложений, маршрутизации и управления состоянием не получится создавать сложные и поддерживаемые Vue приложения. На нашем курсе Vue.js 3, Vue Router и Pinia вы получите все необходимые знания и навыки. В первых 3 модулях уже доступно бесплатное содержание — начните погружаться в мир Vue прямо сегодня.
Частозадаваемые технические вопросы по теме компиляции Vue Core
Почему при использовании runtime-only сборки Vue нельзя использовать опцию template в new Vue?
Vue runtime-only не содержит компилятора шаблонов. Если вы передадите строку в опции template, Vue не сможет её обработать. Используйте render-функцию или собирайте проект через vue-loader/Vite, чтобы шаблон был скомпилирован в JS заранее.
Как посмотреть итоговую render-функцию для своего шаблона?
Можно воспользоваться https://template-explorer.vuejs.org/ — вставьте шаблон и посмотрите, во что он транслируется. Также для Single File Component итоговая функция обычно видна рядом с компонентом после сборки (render.js или атрибут render в исходном JS-файле).
Что делать, если хочется динамически собирать шаблоны на клиенте?
Используйте специальную версию Vue (vue@2: разница между vue.runtime.js и vue.js), а для Vue 3 — подключайте пакет @vue/compiler-sfc и используйте API типа compile. Но старайтесь избегать этого в prod, только если есть реальный use-case.
Как добавить свою кастомную директиву, чтобы она корректно работала после компиляции?
Кастомные директивы, объявляемые через app.directive, автоматически используются в render-функциях после компиляции. Главное — чтобы имя директивы совпадало с используемым в шаблоне.
Почему при ошибках в шаблоне бывают сложные для понимания сообщения?
Ошибки, которые возникают на этапе компиляции, часто указывают на проблему парсинга или невозможность корректного построения AST. Совет: пользуйтесь редакторами с поддержкой linting для Vue (Vetur, Volar) — они подсказывают ошибки заранее.
Постройте личный план изучения Vue до уровня Middle — бесплатно!
Vue — часть карты развития Frontend
100+ шагов развития
30 бесплатных лекций
300 бонусных рублей на счет
Бесплатные лекции
Все гайды по Vue
Лучшие курсы по теме

Vue 3 и Pinia
Антон Ларичев
TypeScript с нуля
Антон Ларичев