Angular2でAoT Compile試してみた

*こちらは[Opt Technologies Advent Calendar 2016](http://qiita.com/advent-calendar/2016/opt-technologies)の12日目になります。
遅刻マンでどうもすみません


---

というわけで[@_sisisin](https://twitter.com/_sisisin)です
Angular2といえばAoTみたいなところがあるらしいのと、webpack2のRCも出たので、そろそろ触ってみる頃合いでは！？という機運を感じたので試してみました


# AoT Compileとは？
- Ahead of Time Compileの略
- Angular2系で書かれたアプリをビルドする際に、templateのhtmlも一緒にコンパイルしちゃおうというもの
- 一言で言ってしまうと、ビルド時に`tsc`の代わりに`ngc(パッケージは@angualr/compiler-cli)`を使うことで実現する
    - *一言で言ったものの、`ngc`を使えるようにするには他にも色々やらなきゃいけないことはもちろんあります
- 概ね @Quramy さんの[Angular AoTガイド](http://qiita.com/Quramy/items/a603ddb47d6e4b3497e1)を参照していただければ色々わかります

# とりあえず最小構成
なにはともあれ最小構成で試してみる

リポジトリ：https://github.com/sisisin-sandbox/ng-aot

## 構成

```
|-- dist/
| `-- budnle.js
|
|-- _tmp/      # TypeScriptのトランスパイル結果ファイル置き場
|
|-- _tmp_aot/  # angular compiler-cliが自動生成するAoT CompileされたTypeScriptファイル置き場
|
|-- src/
| |-- app.component.css
| |-- app.component.html
| |-- app.component.ts
| |-- app.module.ts
| |-- main.aot.ts
| |-- main.ts
| `-- polyfills.ts
|
|- index.html
|- package.json
|- tsconfig.aot.json
|- tsconfig.json
|- webpack.config.dev.js
`- webpack.config.prod.js
```

## 解説
開発時はAoTを使わず、本番ではAoTを利用するというユースケースを想定してます
そのためにAoTを使用する/しないを使い分けるためにwebpack.confやtsconfig,アプリのメインエントリポイントをわけています

### 開発用ビルドについて
開発時は`tsconfig.json`,`webpack.config.dev.js`を利用して`main.ts`をビルドします。

```ts:main.ts
import './polyfills';

import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';
platformBrowserDynamic().bootstrapModule(AppModule);
```

こちらはいつものAngular2系のエントリポイントですね。
`platformBrowserDynamic`で`AppModule`を実行しています。


なお、tsconfigの`exclude`に`main.aot.ts`を入れています。
後述しますが、`main.aot.ts`は`ngc`の生成するtsファイルを参照しているので、普通に`tsc`でビルドしようとするとビルドが通りません


### 本番用(AoT Compile)ビルドについて
本番では`tsconfig.aot.json`,`webpack.config.prod.js`の設定ファイルで`ngc`を利用して`main.aot.ts`をビルドします

```ts:main.aot.ts
import './polyfills';

import { platformBrowser } from '@angular/platform-browser';
import { AppModuleNgFactory } from '../_tmp_aot/app/app.module.ngfactory';
platformBrowser().bootstrapModuleFactory(AppModuleNgFactory);
```

ここでは`@angular/platform-browser`に含まれている`platformBrowser`というモジュールで、`AppModuleNgFactory`を実行しています。

`AppModuleNgFactory`は`ngc`コマンドにて自動で生成されるモジュールになっています。
`ngc`の出力結果には他にも`app.component.css.shim.ngstyle.ts`や`app.component.ngfactory.ts`などがあり、これらはcssやhtmlをTypeScriptのコードに落とし込んだものになっています。
これによって静的解析が出来るようになるわけですね。

### AoTの効果について
開発者ツールを覗いてみました


ファイルサイズ比較

||AoT未使用|AoT使用|
|:--|:--|:--|
|minifyなし|6.4MB|3.2MB|
|minify済み|734KB|342KB|

実行時間比較
AoT未使用+minify
![notaot-timeline.png](https://qiita-image-store.s3.amazonaws.com/0/54872/77d97762-4162-f40c-cfbd-814aca2871d1.png)

AoT使用+minify
![aot-timeline.png](https://qiita-image-store.s3.amazonaws.com/0/54872/830cf259-1250-8d67-74e7-9654af711744.png)

|AoT未使用|AoT使用|
|:--|:--|
|388ms|166ms|

AoT未使用だと大体300~400msかかっていますが、AoT使用だと160~200msぐらいに収まっています（AoT使用でidleがやたら長いのが気になりますが。。。


にしても歴然の差ですね。
hello worldレベルのコードでこの差なので絶対に取り入れたいという気持ちが強くなります
さすがに実行時間についてはそんなに変わらないだろと思ったのに結構バッチリ差が出てて笑っちゃいました

# まとめ
Angular2系をやるならぜひともAoTはやってやっていこう！


# おまけ
compiler-cli@2.3.1では不具合があるようで、TypeScript2.1.3で`ngc`を実行すると`ngfactory.ts`を吐き出してくれません。
自分はこれで半日近く悩まされました。。。

https://github.com/angular/angular/issues/13204
issueも上がっているようなので遠からず解決することでしょう。

ご利用の際はお気をつけて。