Ahead-of-Time (AOT)編譯
在Angular 2 中有兩種編譯模式:
- JIT(Just-in-Time):Angular預設是使用 Just-in-Time (JIT) 即時編譯,等瀏覽器下載完 *.js 檔案後,會在用戶端的瀏覽器編譯 Angular 的 JS 程式碼,接著才會渲染畫面。
- AOT(Ahead-of-Time):在程式發佈之前就透過 Angular Compiler 進行編譯,所以瀏覽器下載完的 *.js 檔案,就可以直接被執行,然後渲染畫面。
下表為這兩種佈署方式的簡單比較表:
| Characteristic | JiT | AoT | 
|---|---|---|
| Compilation target | Browser | Server | 
| Compilation context | Runtime | Build | 
| Bundle size | Huge (~1.2 MB) | Smaller (~400 KB) | 
| Execution Performance | – | Better | 
| Startup time | – | Shorter | 
AoT的要點是將編譯從運行時移動到構建過程。因此我們不需要讓用戶載入完整的編譯器功能,也不需要在用戶端才去做編譯的動作,所以從對照表可以看出,這個動作可以讓效能以及檔案大小都變得更好。
另外,預先編譯可以在編譯期就發現一些模版的錯誤,而不需要等到實際在客戶端執行才發現。使用AOT,編譯器僅僅使用一組庫在構建期間運行一次;使用JIT,編譯器在每個用戶的每次運行期間都要用不同的庫運行一次。
AOT編譯的優點
- 更快:瀏覽器直接載入可運行的程式碼,可以立即使用,而不用等待編譯完成。
- 減少HTTP異部請求:編譯器把外部HTML模板和CSS樣式表內聯到了該應用的JavaScript中。消除了用來下載那些源文件的Ajax請求。
- 檔案更小:客戶端不用載入完整的Angular編譯器
- 提早檢測模板錯誤:編譯時會跳出模板綁定錯誤警告,提早發現錯誤
- 更安全:AOT編譯遠在HTML模版和組件被服務到客戶端之前,將它們編譯到JavaScript文件。沒有模版可以閱讀,沒有高風險客戶端HTML或JavaScript可利用,所以注入攻擊的機會較少。
使用AOT編譯
Angular5大大的簡化了AOT流程,我們只需在生成文件時加上--aot
ng build –aot
ng serve –aot
如果我們使用--prod預設也會是aot輸出。
用AOT編譯的程式編寫限制
如果使用AOT預編譯,在撰寫angular的metadata要注意下面幾點:
不支援function expression
var myFunction = function [name]([param1[, param2[, ..., paramN]]]) {
   statements
};
不支援Arrow functions
(param1, param2, …, paramN) => { statements }
像下面這種設定方法在AOT是不被支援的
@Component({
  ...
  providers: [{provide: server, useFactory: () => new Server()}]
})
需改成這樣:
export function serverFactory() {
  return new Server();
}
@Component({
  ...
  providers: [{provide: server, useFactory: serverFactory}]
})
在元數據內單獨使用常數
因為常數是在編譯時就編譯進JS裡,如下面的寫法會造成AOT在編譯時遺失template常數的值:
const template = '<div>{{hero.name}}</div>';
@Component({
  selector: 'app-hero',
  template: template
})
export class HeroComponent {
  @Input() hero: Hero;
}
我們可以改用下面這種寫法
@Component({
  selector: 'app-hero',
  template: '<div>{{hero.name}}</div>'
})
export class HeroComponent {
  @Input() hero: Hero;
}
或將常數放至一個運算表達式內:
const template = '<div>{{hero.name}}</div>';
@Component({
  selector: 'app-hero',
  template: template + '<div>{{hero.title}}</div>'
})
export class HeroComponent {
  @Input() hero: Hero;
}
裝飾和數據綁定的類成員必須公開
在metadata中只支援下面的angular decorators
| DECORATOR | MODULE | 
|---|---|
| Attribute | @angular/core | 
| Component | @angular/core | 
| ContentChild | @angular/core | 
| ContentChildren | @angular/core | 
| Directive | @angular/core | 
| Host | @angular/core | 
| HostBinding | @angular/core | 
| HostListener | @angular/core | 
| Inject | @angular/core | 
| Injectable | @angular/core | 
| Input | @angular/core | 
| NgModule | @angular/core | 
| Optional | @angular/core | 
| Output | @angular/core | 
| Pipe | @angular/core | 
| Self | @angular/core | 
| SkipSelf | @angular/core | 
| ViewChild | @angular/core | 
如果表達式使用不受支持的語法,則collector將錯誤的項目寫入.metadata.json文件。如果編譯器需要這段元數據來生成應用程序代碼,則編譯器稍後將報告該錯誤。
若希望能立即顯示錯誤,則可以將tsconfig的strictMetadataEmit設為true
“angularCompilerOptions”: {
  …
  “strictMetadataEmit” : true
}