Компиляция Angular — обзор (с чего начать)

Прежде чем нырять в детали, надо разложить по полочкам какие вообще бывают компиляции в Angular. Слово «компиляция» тут перегружено — это сбивает с толку. Есть три независимых оси:

Ось 1. Когда компилируется шаблон: JIT vs AOT

JIT (Just-in-Time) AOT (Ahead-of-Time)
Когда в браузере, при старте при сборке, на твоей машине/CI
Кто @angular/compiler едет в бандл ngtsc (компилятор внутри сборки)
Скорость старта медленнее (компилит на лету) быстрее (готовый JS)
Размер бандла больше (тащит компилятор) меньше (компилятор не нужен в рантайме)
Где сейчас только ng test/редкие случаи дефолт для v21 (ng build, ng serve)

В v21 всё AOT. JIT остался как legacy. Поэтому весь наш разбор — про AOT.

Ось 2. Что на входе: твой код (app) vs чужая библиотека (lib)

Тут и живёт «partial Ivy», про который был вопрос. Две разные ситуации:

Приложение (твой код) Библиотека (npm-пакет)
Чем собирается ng build твоего app ng-packagr авторами либы
Режим компиляции full (полный Ivy) partial (частичный)
Что на выходе ɵɵdefineComponent({...}) — финальные инструкции ɵɵngDeclareComponent({...}) — «декларация»: шаблон строкой + метаданные
Кто доводит до конца — (уже готово) Linker при сборке твоего app

Зачем так? Если бы либа публиковалась в full-Ivy, её формат был бы жёстко привязан к версии Angular (инструкции меняются от версии к версии — мы это видели: ɵɵelementStartɵɵdomElementStart). Partial-формат стабилен между версиями: либа говорит «вот мой шаблон и метаданные», а конкретные инструкции генерит linker той версии Angular, которой собирают приложение. Это развязывает версии либы и app.

→ Полный разбор: 02-partial-ivy-and-linker

Ось 3. Кто превращает результат в загружаемый файл: bundler

Компилятор (ngtsc/linker) выдаёт JS-модули. Их ещё надо собрать в бандл, минифицировать, дать dev-сервер. Этим занимается bundler — и он менялся:

  • v14: webpack (медленный, но гибкий).
  • v21: esbuild (Go, в десятки раз быстрее) + vite (dev-сервер с HMR).

→ Почему сменили и как устроено: 03-build-tooling

Как три оси складываются в одну сборку ng build

твой App.ts (@Component)        npm-либа (@ngDeclareComponent)
      │  ngtsc: FULL AOT              │  уже partial (собрана ng-packagr)
      ▼                              ▼
ɵɵdefineComponent({...})       LINKER: ngDeclare → ɵɵdefineComponent
      │                              │   (та же full-генерация, версия твоего app)
      └──────────────┬───────────────┘
                     ▼
              bundler (esbuild/vite): bundle + minify + tree-shake
                     ▼
              dist/.../main.js  → грузится в браузер

То есть и твой код, и библиотеки в итоге сходятся в одинаковые Ivy-инструкции — просто твой код проходит full-путь сразу, а либы доводит linker.

Куда дальше

  1. 01-full-pipelineглавная заметка: как ngtsc гонит твой шаблон через 7 стадий (HTML AST → render3 AST → IR → фазы → reify → emit → defineComponent).
  2. 02-partial-ivy-and-linker — как собираются и «дотягиваются» библиотеки.
  3. 03-build-tooling — webpack vs esbuild/vite, почему так и как ngtsc встроен в сборку.