Dev Study
← 解説「AOTコンパイル — テンプレートは命令列に変換される」に戻る

サンプルコードで身につける: AOTコンパイル — テンプレートは命令列に変換される

解説で学んだ概念を、5つの具体例で確認します。素朴な例から実務寄りの例へと進みます。

1バインディング記法と命令の対応表

コースの序盤で学んだテンプレート記法は、それぞれ決まった命令に変換されます。この対応を知ると「記法を覚える」から「変換先を知っている」に理解が一段深まります。

// ── テンプレート記法 → コンパイル後の命令(概念)──
//
// {{ title() }}          → ɵɵtextInterpolate(ctx.title())
//   テキストノードの中身を差し替える
//
// [src]="url()"          → ɵɵproperty('src', ctx.url())
//   DOMプロパティへ値を流し込む
//
// (click)="save()"       → ɵɵlistener('click', ...)
//   作成モードで1回だけリスナーを登録する
//
// @if / @for             → ɵɵtemplate(...) + コンテナ
//   中身を「下書き」として登録し、条件で実体化する
//   (レガシー編で学んだ ng-template の機構がこれ)

2作成モードと更新モードのタイムライン

同じテンプレート関数が、初回と2回目以降で別のブロックを実行します。ボタンを3回押したときに何がどれだけ走るかを時系列で見ると、「2回目以降は差し替えだけ」が具体的に分かります。

// template: '<p>{{ count() }}</p>' の一生
//
// 初回表示:
//   rf & 1(作成): p要素を作る / テキストノードを作る
//   rf & 2(更新): count() の値 0 を書き込む
//
// count.set(1):
//   rf & 2(更新)だけ: 前回値0 ≠ 今回1 → テキスト差し替え
//
// count.set(1) をもう一度:
//   rf & 2(更新)だけ: 前回値1 = 今回1 → DOMに触らず終了
//
// p要素を「作る」処理は初回の1回しか実行されない。
// Virtual DOM のような毎回のツリー構築・比較は存在しない

3コンパイル済みコードを自分の目で見る

ビルド成果物を覗くと、ɵɵ付きの命令が本当に入っていることを確認できます。難読化を切ってビルドすると読みやすくなります。一度見ておくと「テンプレートはJSになる」が実感に変わります。

# 難読化なしでビルドすると成果物が読める
ng build --configuration development

# 成果物から自分のコンポーネントを探す
grep -o 'ɵɵelementStart([^)]*)' dist/my-app/browser/main-*.js | head
#   ɵɵelementStart(0, "h1")
#   ɵɵelementStart(2, "button", 0)
#   ...

# テンプレートに書いた h1 や button が、
# 「要素を作る関数呼び出し」としてJSの中に並んでいる。
# index.html には相変わらず <app-root> しか無い

4AOTとJIT — コンパイルはいつ走るか

現在はAOT(ビルド時コンパイル)が標準ですが、古いプロジェクトや動的なテンプレート生成ではJIT(実行時コンパイル)に出会うことがあります。違いは「変換をどこでやるか」だけで、変換内容は同じです。

// ── AOT(現在の標準)──
//   ビルド時: テンプレート → 命令列 に変換して同梱
//   実行時:   変換済みの関数を実行するだけ
//   利点:     起動が速い・バンドルが小さい(コンパイラ不要)
//             テンプレートの誤りがビルド時に見つかる
//
// ── JIT(レガシー/特殊用途)──
//   ビルド時: テンプレートを文字列のまま同梱
//   実行時:   ブラウザ内でコンパイラが変換してから実行
//   痕跡:     古い設定の "aot": false や
//             @angular/compiler の実行時import
//
// テンプレートの型チェック(strictTemplates)がビルドで効くのは
// AOTが「テンプレートもコンパイル対象」として扱うから

5ɵɵ入りスタックトレースの読み方

実行時エラーのスタックトレースにɵɵ関数が並んでいたら「テンプレート由来のエラー」というサインです。デバッグ編で学んだエラーの読み方に、内部機構の知識を足すとさらに絞り込めます。

// ERROR TypeError: Cannot read properties of undefined ('name')
//   at UserCardComponent_Template  ← テンプレート関数の中!
//   at executeTemplate
//   at refreshView               ← 更新モードの実行中
//   at detectChangesInternal     ← 変更検知から呼ばれた
//
// 読み取れること:
//   ・XxxComponent_Template → どのコンポーネントのテンプレートか
//   ・refreshView 系が並ぶ → 更新モード(=変更検知中)のエラー。
//     初回表示は通ったが、ある更新のタイミングで値が壊れた
//   ・{{ user.name }} で user が undefined になる瞬間がある、
//     という仮説が立つ → @if (user(); as u) でガードする