Dev Study
← Angular コース

74. AOTコンパイル — テンプレートは命令列に変換される

このセクションでは、Angularで書いたコードがどう変換されてブラウザで動いているのか、という土台を掘り下げます。出発点はこの事実です: ブラウザはAngularのテンプレートを一切見ていません。ビルド時にAngularコンパイラ(ngtsc)が @Component のテンプレートを解析し、「DOMを組み立てるJavaScript命令の列」であるテンプレート関数に変換して、クラスの静的プロパティ(ɵcmp)として埋め込みます。これがAOT(Ahead-of-Time)コンパイルで、実行時のブラウザにはコンパイラを届けないので、その分軽く・速く・エラーはビルド時に見つかります。

変換されたテンプレート関数は2部構成です。作成モード(初回に1回だけ走る)は elementStart や text といった「要素を作る」命令、更新モード(変更検知のたびに走る)は「値を差し替える」命令だけを持ちます。つまり「箱を作る仕事」と「中身を入れ替える仕事」がコンパイル時点で分離されていて、2回目以降の描画では作成命令は一切走りません。Reactのように毎回仮想ツリーを作って前回と比較する方式(Virtual DOM)とは、ここが根本的に違います。

もう1つの設計思想が局所性です。各コンポーネントは他のコンポーネントと独立にコンパイルされ、そのテンプレートが実際に使う命令関数だけがバンドルに残ります(tree-shaking)。レガシーのセクションで「@if も *ngIf も同じ機構に落ちる」と学びましたが、その行き先がこの命令列の世界です。スタックトレースに ɵɵ 付きの関数名が出てきたら、「いまテンプレート由来のコードの中にいる」と読めるようになります。

サンプルコード(フレームワーク環境が必要なため表示のみ)

// 書いたコード
@Component({ template: '<h1>{{ title() }}</h1>' })
export class AppComponent {
  title = signal('こんにちは');
}

// ビルド後の概念図: クラスにテンプレート関数が埋め込まれる
// AppComponent.ɵcmp = defineComponent({
//   template: (rf, ctx) => {
//     if (rf & 1) {              // 作成モード: 初回だけ
//       ɵɵelementStart(0, 'h1'); // 0番スロットに h1 を作る
//       ɵɵtext(1);               // 1番スロットにテキストノード
//       ɵɵelementEnd();
//     }
//     if (rf & 2) {              // 更新モード: 変更検知のたび
//       ɵɵadvance(1);
//       ɵɵtextInterpolate(ctx.title()); // 値の差し替えだけ
//     }
//   },
// });
サンプルコードで身につける(5本) →

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

公式ドキュメントで詳しく ↗