01 — Компиляция: из шаблона в JS-функцию

Цель главы: понять, что твой шаблон не доезжает до браузера как HTML. Он превращается в обычную JavaScript-функцию ещё на твоём компьютере.

Проблема, которую решает компилятор

Браузер понимает только две вещи:

  • JavaScript (логика);
  • DOM (дерево HTML-элементов: создать <p>, поменять текст, удалить).

А ты пишешь вот это:

<p>Счётчик: {{ count() }}</p>
@if (count() > 2) { <p class="big">Больше двух!</p> }

Браузер не знает, что такое {{ }} и @if. Значит, кто-то должен это перевести в «создай <p>, положи туда число, а вон тот блок показывай только если count > 2». Этим занимается компилятор Angular — и делает он это заранее, при сборке (AOT — Ahead Of Time, «заранее»).

Что получается на выходе

Каждый компонент превращается в вызов ɵɵdefineComponent({...}), внутри которого — template-функция. Упрощённо она выглядит так:

function App_Template(rf, ctx) {
  if (rf & 1) {            // режим СОЗДАТЬ (первый раз)
    element('p');          //   создать <p>
    text(1);               //   создать пустой текстовый узел внутри
  }
  if (rf & 2) {            // режим ОБНОВИТЬ (каждый раз потом)
    advance(1);
    textInterpolate1('Счётчик: ', ctx.count(), '');  // вписать число
  }
}

Запомни эти два режима — это сердце всего Angular:

  • rf & 1create (создание). Выполняется один раз: строит DOM-каркас.
  • rf & 2update (обновление). Выполняется при каждой проверке: вписывает свежие значения в уже существующий DOM.

Одна и та же функция и строит, и обновляет — просто в разных режимах. Поэтому Angular не перерисовывает всё заново, а точечно меняет текст/атрибуты.

Анимация: путь шаблона по конвейеру

assets/compile-flow.svg

Если кадры не проигрались, вот то же самое по шагам (это и есть «кадры»):

Кадр 1:  "<p>Счётчик: {{ count() }}</p>"     ← просто строка
Кадр 2:  HTML-дерево:  <p> ─ text("Счётчик: ") ─ {{ }}   ← разобрали теги
Кадр 3:  список операций:  [создать <p>] [создать text] [обновить text = count()]
Кадр 4:  числа вместо имён: слот 0 = <p>, слот 1 = text
Кадр 5:  готовые вызовы:  element('p'); textInterpolate1('Счётчик: ', count())

Каждый кадр — это отдельная стадия компилятора. Их там около 70, но идея одна: строка → дерево → список простых операций → JS-инструкции.

Что станет с нашими конструкциями

Ты написал Во что превратится Простыми словами
{{ count() }} textInterpolate1(..., count()) «впиши число в текст»
(click)="inc()" listener('click', () => inc()) «повесь обработчик клика»
@if (count() > 2) conditional(count() > 2 ? 0 : -1) «показывай блок 0 или ничего»
@for (n of items()) repeater(items()) «повтори блок для каждого элемента»

Заметь: @if и @for — это не магия в браузере. Это обычные функции conditional и repeater, которые создают/удаляют куски DOM по условию.

Важный вывод

После компиляции в браузер едет только JavaScript. Никаких {{}}, @if, @for там уже нет — есть функция, которая знает, что и когда нарисовать. Поэтому Angular-приложение стартует быстро: браузеру не надо «разбирать шаблоны», всё уже переведено.

Дальше: эту функцию (и весь остальной код) надо упаковать в файл, который скачает браузер → 02 — Build.