iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 27
2

Ahead-of-Time (AOT)編譯

在Angular中有兩種編譯模式:

  • 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文件。如果編譯器需要這段元數據來生成應用程序代碼,則編譯器稍後將報告該錯誤。

若希望能立即顯示錯誤,則可以將tsconfigstrictMetadataEmit設為true

"angularCompilerOptions": {
  ...
  "strictMetadataEmit" : true
}

參考資料


上一篇
[技術支援-4] Angular Universal
下一篇
[技術支援-6] NPM設定
系列文
用30天深入Angular 5的世界31

1 則留言

0
微中子
iT邦新手 4 級 ‧ 2018-01-18 03:38:47

沒想到我的文章也在參考之中。
現在回去看覺得慘不忍睹 XD

Angular CLI 預設成 AOT 之後,平常就沒啥感覺了,去年要編個 AOT 都一堆麻煩

我有拜讀你去年的系列文喔!
[[功能介紹-1] Angular架構]([功能介紹-1] Angular架構)這篇你的文章也有在參考之中!
AOT現在真的方便多了...參考文章裡的方法都好複雜阿!

我要留言

立即登入留言