
之前用 Angular 4 (Angular 2) 開發後台系統,使用者都是在 PC 上面使用,網站啟動速度都很快,所以沒有使用到 Ahead-of-Time (AOT) 預先編譯的需求。
最近新產品上線,遇到很多 Android 的使用者開啟網站超級慢,舊一點的機型甚至開一分鐘才有畫面。事後才趕緊補上 AOT 編譯。
本篇將介紹用 Webpack 預先編譯 AOT 編譯。
AOT vs JIT
開發 Angular 所撰寫的 TypeScript 透過 TypeScript Compiler 產生出來的 *.js 檔,是屬於 Angular 的 Source Code,必須經由 Angular Compiler,才能在瀏覽器中執行。
而 Angular Compiler 可以在兩個不同的階段進行編譯:
Just-in-Time (JIT)
Angular 預設是使用 Just-in-Time (JIT) 即時編譯,等瀏覽器下載完 *.js 檔案後,會在用戶端的瀏覽器編譯 Angular 的 JS 程式碼,接著才會渲染畫面。
優點:
*.js檔案是 Angular 的原始碼,所以檔案較小。
缺點:
在用戶端的瀏覽器編譯,所以網站啟動速度會較慢。
Ahead-of-Time (AOT)
Ahead-of-Time (AOT) 預先編譯,是在程式發佈之前就透過 Angular Compiler 進行編譯,所以瀏覽器下載完的 *.js 檔案,就可以直接被執行,然後渲染畫面。
優點:
減少掉了在用戶端的瀏覽器編譯的時間,所以網站啟動速度會較快。
缺點:
由於
*.js是經過編譯後的檔案,所以檔案會較大。
範例程式碼
我用之前Angular 4 教學 - 從頭開始的範例延伸。
初始結構檔案結構如下:
1  | index.html # 起始頁面  | 
安裝 Webpack 套件
安裝 Webpack 及接下來範例打包所需的開發套件,指令如下:
1  | npm install --save-dev webpack angular2-template-loader awesome-typescript-loader raw-loader  | 
Webpack 設定
新增 webpack.config.js
1  | var webpack = require("webpack");  | 
執行 webpack
打包指令如下:
1  | webpack -p  | 
修改 index.html 參考 *.js 的位置:
1  | 
  | 
打開網頁用瀏覽器的開發工具,看到 bundle-vendors.js 及 bundle.js 檔案大小及載入時間:

到目前為止,只是改成用 Webpack 打包 Angular 的 Source Code,所以還只是 JIT 編譯。
由於本篇範例實在是太簡單了,看到載入的速度很快,才 400/ms 左右。
安裝 AOT 套件
AOT 編譯所需的套件,除了 bundle-vendors 設定中的 11 個套件,還需要額外安裝 @angular/compiler-cli 及 @angular/platform-server,指令如下:
1  | npm install --save @angular/compiler-cli @angular/platform-server  | 
TypeScript 設定
編輯 tsconfig.json,設定 AOT 編譯後的檔案輸出位置:
1  | {  | 
基本上 tsconfig.json 的設定跟原本差不多,新增了 files 及 angularCompilerOptions。
files指定 Module 的位置,如果是 Lazy Loading,這邊就要加入所有 Lazy Loading 的 Module。genDir指定 AOT 編譯後的檔案輸出位置。
我的範例程式中,為了保留 AOT 及 JIT 的差異,所以另外新增了一個
tsconfig-aot.json的檔案,並保留原本的tsconfig.json。
AOT 編譯
套件安裝完也設定完成後,就可以用 ngc 指令進行 AOT 編譯:
1  | node_modules/.bin/ngc -p tsconfig-aot.json  | 
編譯成功後,檔案結構如下:
1  | index.html # 起始頁面  | 
更新程式進入點
編輯 main.ts
1  | // JIT 啟動 AppModule 用法  | 
由於 AppModule 已經透過 AOT 編譯成 AppModuleNgFactory,所以載入 Module 不再使用 platformBrowserDynamic 動態載入,改為用 platformBrowser 載入 AppModuleNgFactory。
再次執行 Webpack 打包後,打開網頁用瀏覽器的開發工具,看到 bundle-vendors.js 及 bundle.js 檔案大小及載入時間:

可以看到 bundle.js 的檔案大小差異非常的大,從原本的 1.8 KB 變成 4.6 KB。
頁面載入速度稍微快了一點,從原本的 400/ms 變為 250/ms 左右,因為範例太簡單,所以速度差的沒有很多。
但隨著系統規模越做越大及程式複雜度提升,速度就會有非常明顯的差異。
bundle-vendors.js變小是因為我把@angular/*移除了。
補充
換成用 Webpack 打包後,npm 套件 systemjs 就用不到了,可以從 package.json 中移除,或用指令移除:
1  | npm uninstall systemjs --save  | 
system.config.js 也可以隨之移除。
改成用 AOT 編譯後,前端不再需要動態編譯,所以在 bundle-vendors 中可以把 @angular/* 移除:
1  | var webpack = require("webpack");  | 
建議
根據我的經驗以及網路上的資訊,PC 及 iPhone 在執行 Angular JIT 編譯時,速度都還算蠻快的,而且差異不太大。
而 Android 不論是新舊機型或任何瀏覽器,執行 Angular JIT 編譯的速度都明顯比 PC 及 iPhone 慢,舊一點的機型甚至開一分鐘才有畫面。
類似的問題:angular2 loading slow on android(had use lazy loading)
所以,如果產品需要支援手機或嵌入式裝置等,建議一開始就使用 AOT。
如果只需要支援 PC 版,用 JIT 會較省下載速度及流量,可以比較不用擔心啟動效率問題。
程式碼下載
參考
Ahead-of-Time Compilation
Angular2 AOT with Webpack and Lazy Loading
angular2 loading slow on android(had use lazy loading)