В чем разница между Ahead-of-Time и Just-in-Time компиляциями в Angular?
Что проверяют
Понимаете ли вы, что происходит с шаблонами компонентов между исходниками и браузером, и знаете ли, какой режим сейчас работает по умолчанию. Следом часто спрашивают, где JIT в современном Angular ещё встречается и почему AOT ловит ошибки, которые JIT пропускает.
Как отвечать
Шаблон Angular это не HTML, который браузер понимает сам: его нужно превратить в JavaScript-инструкции, создающие и обновляющие DOM. Разница в том, когда это делается.
- JIT (Just-in-Time): шаблоны компилируются в браузере при запуске. В бандл едет сам компилятор из
@angular/compiler, приложение стартует медленнее, а ошибка в шаблоне всплывает только в рантайме, у пользователя; - AOT (Ahead-of-Time): компиляцию делает компилятор Angular на этапе сборки. В браузер уходит готовый код компонентов, компилятор не нужен, старт быстрее, бандл меньше;
- проверка шаблонов: при AOT шаблон проходит проверку типов, а с
strictTemplatesвangularCompilerOptionsкомпилятор ругается на несуществующее свойство или неверный тип инпута ещё до деплоя; - безопасность: шаблоны не собираются из строк в рантайме, поэтому меньше поверхность для инъекций в шаблон.
Главное, что стоит сказать: начиная с Ivy (Angular 9) AOT включён по умолчанию и для ng build, и для ng serve, так что схемы «JIT в разработке, AOT в проде» больше нет. JIT остался в юнит-тестах: TestBed по умолчанию компилирует компоненты на лету. Библиотеки публикуются в частично скомпилированном виде и доводятся линкером при сборке приложения, отдельный ngcc убран.
Про размер бандла точнее так: неиспользуемый код вырезает сборщик, а AOT убирает из бандла компилятор и даёт код, удобный для tree shaking.
Где спотыкаются
Говорят, что JIT нужен для быстрой разработки. Это было верно до Angular 9, сейчас dev-сервер тоже собирает в AOT, а скорость пересборки даёт инкрементальная компиляция.
Путают AOT с минификацией и tree shaking. Это разные этапы: AOT отвечает за шаблоны, остальное делает сборщик.
Не знают, что при AOT нельзя скомпилировать шаблон из строки, пришедшей с сервера. Для динамики используют ViewContainerRef.createComponent с заранее известными компонентами.