03 — Bootstrap: как приложение запускается

Цель: понять, что происходит между «браузер скачал main.js» и «на экране появился счётчик: 0».

Точка входа

В main.ts одна строчка:

bootstrapApplication(App);

bootstrap = «запустить с нуля» (как «завести машину»). Эта функция и раскручивает всё приложение.

Что происходит по шагам

1. index.html в браузере:  <body><app-root></app-root></body>   ← пустое место
2. main.js выполняется → bootstrapApplication(App)
3. создаются инжекторы (склад зависимостей)
4. запускаются инициализаторы (если есть)
5. Angular ищет <app-root> на странице  ← единственный реальный поиск в DOM!
6. создаёт экземпляр класса App (через DI)
7. вызывает template-функцию в режиме СОЗДАТЬ (rf & 1)
8. внутри <app-root> появляются <h1>, <p>Счётчик: 0</p>, кнопка...

Разберём непонятные места.

Шаг 3 — «инжекторы» простыми словами

Инжектор — это склад готовых объектов (сервисов). Когда твоему компоненту нужен, скажем, HttpClient, он не создаёт его сам — просит у склада: «дай мне HttpClient». Склад либо выдаёт уже готовый, либо создаёт и запоминает.

Зачем: один и тот же сервис переиспользуется везде (не плодим копии), и его легко подменить (например, в тестах). Это и есть DI — Dependency Injection, «впрыск зависимостей».

При старте создаётся два уровня склада:

  • корневой (на всё приложение) — туда кладутся provide...() из bootstrap;
  • окружение — служебные вещи рантайма.

Шаг 5 — единственный настоящий поиск в DOM

Вот это важно и часто путают: Angular ищет элемент в живой странице ровно один раз — когда находит <app-root> для корневого компонента (по его selector).

Всё остальное (где какой дочерний компонент, какая директива) определяется не поиском в DOM, а заранее — на компиляции. Подробно про это → 07 — Селекторы.

Шаг 7 — первый рендер (режим «создать»)

Помнишь два режима template-функции из главы 01? При старте вызывается режим create (rf & 1):

<app-root>
  ├─ <h1>demo21</h1>            ← создан
  ├─ <p>Счётчик: 0</p>         ← создан, число = 0 (начальное)
  ├─ <p>Удвоенный: 0</p>       ← создан
  ├─ <button>+1</button>       ← создан + повешен (click)
  ├─ (@if: count > 2? нет → блок НЕ создан)
  └─ <ul></ul>                  ← пустой (@for: items() = [], 0 элементов)

Так как count = 0:

  • @if (count() > 2) ложно → блок «Больше двух!» не создаётся вообще;
  • @for (n of items())items() пустой массив → ноль <li>.

После этого один раз срабатывают хуки «после первого рендера» (afterNextRender).

Что в итоге на экране

demo21
Счётчик: 0
Удвоенный: 0
[ +1 ]

Приложение запущено, DOM построен. Дальше оно просто ждёт, пока ты что-нибудь нажмёшь. Что произойдёт при клике — в следующей главе.

Дальше → 04 — Runtime и change detection.