為什么需要編譯
Angular應(yīng)用中包含的組件、HTML模板(比如:@Directive、@Component、@NgModule、@Pipe)很多都是JS VM無法解析的,所以在瀏覽器渲染應(yīng)用之前,組件和模板必須要被Angular編譯器轉(zhuǎn)換為可以執(zhí)行的JavaScript。
angular2編譯模式
在 Angular 2 中有兩種編譯模式:
- JIT - Just-In-Time
- AOT - Ahead-Of-Time
JIT事件流:
開發(fā)流程:
- 使用TypeScript開發(fā)Angular應(yīng)用(此處以ts舉例)
- tsc編譯
- 構(gòu)建
- 壓縮
- 部署
用戶打開瀏覽器,他將經(jīng)歷以下步驟 (沒有嚴(yán)格的CSP):
- 下載所有的JavaScript資源
- 啟動Angular
- 通過JIT 編譯處理生產(chǎn)js代碼
-
渲染應(yīng)用
AOT事件流:
- 使用Typescript開發(fā)Angular 應(yīng)用
- 使用 ngc來編譯應(yīng)用(目前的ngc編譯報錯還不太好用,angular團(tuán)隊正在用tsc的方式進(jìn)行優(yōu)化,據(jù)說很快就會發(fā)包)
- 模板會被ngc編譯成TypeScript文件(通常是)
- TypeScript編譯為JavaScript代碼
- 構(gòu)建
- 壓縮
- 部署
用戶打開瀏覽器,他將經(jīng)歷以下步驟:
- 下載所有的資源
- 啟動Angular
-
渲染應(yīng)用
aot將compile的過程放在應(yīng)用部署前,所以瀏覽器端承載的工作量就會大幅度減少,相應(yīng)的頁面加載時間也會大幅度減少,這也就意味著更快更好的用戶體驗。
JIT vs AOT:
| 編譯方式 | 編譯時機 | 構(gòu)建速度 | 打包大小 | 性能/渲染速度 | 模板錯誤檢查時間 | 安全性 |
|---|---|---|---|---|---|---|
| JIT | app運行時 | 快 | - | - | app運行時 | 低 |
| AOT | app構(gòu)建階段 | 慢 | - | 更快 | app構(gòu)建階段 | 高 |
AOT優(yōu)勢:
渲染得更快
使用AOT,瀏覽器下載預(yù)編譯版本的應(yīng)用程序。 瀏覽器直接加載運行代碼,所以它可以立即渲染該應(yīng)用,而不用等應(yīng)用完成首次編譯,我們兩個項目AOT加載速度相比JIT有3-5倍的提高需要的異步請求更少
編譯器把外部HTML模板和CSS樣式表內(nèi)聯(lián)到了該應(yīng)用的JavaScript中。 消除了用來下載那些源文件的Ajax請求。需要下載的Angular框架體積更小
如果應(yīng)用已經(jīng)編譯過了,自然不需要再下載Angular編譯器了。 該編譯器差不多占了Angular自身體積的一半兒,所以,省略它可以顯著減小應(yīng)用的體積。但是angular采用 Code Generation 的方式,生成的 ts/js 代碼肯定是會比原來的 html 的文件大小要大的,所以在應(yīng)用足夠大(模版足夠多)的情況下 AOT 的大小是可以反超 JIT 的大小的,很不幸,我們項目就是如此提早檢測模板錯誤
AOT編譯器在構(gòu)建過程中檢測和報告模板綁定錯誤,避免用戶遇到這些錯誤。更安全
AOT編譯遠(yuǎn)在HTML模版和組件被服務(wù)到客戶端之前,將它們編譯到JavaScript文件。沒有模版可以閱讀,沒有高風(fēng)險客戶端HTML或JavaScript可利用,所以注入攻擊的機會較少
JIT優(yōu)勢:
編譯時間短,除非確實有動態(tài)組件的需求,否則jit唯一的優(yōu)勢就是能用來做在線 Demo和開發(fā)調(diào)試,參考知乎答案
我們兩個項目AOT和JIT對比效果:
項目A:
| 編譯方式 | 打包大小 | 渲染速度 |
|---|---|---|
| JIT | 5.86M | ![]() |
| AOT | 10.8M | ![]() |
項目B:
| 編譯方式 | 打包大小 | 渲染速度 |
|---|---|---|
| JIT | 4.12M | ![]() |
| AOT | 6.21M | ![]() |
官方在View 和 DI 上了 View Engine 后aot編譯后沒有太多靜態(tài)文件了,目前aot的編譯大小已經(jīng)低于jit(2017/10/19更新)
懶加載
懶加載也叫延遲加載,即在需要的時候進(jìn)行加載,隨用隨載
在單頁面應(yīng)用中,如果沒有應(yīng)用懶加載,進(jìn)入首頁時會導(dǎo)致需要加載的內(nèi)容過多,延時過長,不利于用戶體驗
運用懶加載將頁面進(jìn)行劃分,按需加載頁面,可以分擔(dān)首頁所承擔(dān)的加載壓力,減少加載用時
如果對首屏啟動有更嚴(yán)格的要求,最好采用服務(wù)端渲染
angular2懶加載可以參考官方文檔
搖樹優(yōu)化:
作用:消除unused code
原理:通過跟蹤import和export語句進(jìn)行靜態(tài)分析,排除那些被導(dǎo)出過但又從未被導(dǎo)入的代碼(ES6 modules 的靜態(tài)特性)
目前大部分工具只能對ES2015模塊搖樹,因為那里有import和export語句,所以需要將ts編譯成es2015(通過tsconfig配置實現(xiàn))
- 搖樹優(yōu)化詳細(xì)介紹可以參考angular官方文檔
- gulp+rollup搖樹優(yōu)化可以參考angular-seed
- webpack2自帶了tree-shaking,配置可以參考工程angular-starter
- angular-cli搭建工程:推薦使用,已經(jīng)幫你集成,不需要再去繁瑣配置各種打包搖樹優(yōu)化等
webpack2的搖樹和rollup搖樹區(qū)別可以參考知乎上這個回答
webpack2注意事項
項目目前使用的是webpack2,總結(jié)了下開發(fā)過程中遇到的坑:
- ngc-webpack不要設(shè)置resourceOverride,否則打包后的圖片url等會有問題
- "JavaScript heap out of memory"可以通過設(shè)置node參數(shù) node --max_old_space_size=4096(如不管用,參數(shù)可以設(shè)置更大試試)
- typescript使用2.0以上版本(搖樹需要)
- 使用awesome-typescript-loader包的2.x及以上版本(搖樹需要)
- 保證我們的應(yīng)用和Angular2庫代碼在同一個位置(搖樹需要)
- UglifyJsPlugin壓縮代碼, Webpack2可以刪除Bundle中未使用的引用代碼,但不會從Bundle中刪除未使用的代碼,在這種情況下就需要使用UglifyJsPlugin,它能夠智能的移除未使用的代碼
- 使用AOT在build時,瀏覽器渲染快,但是在模板足夠多的情況下大于jit打包體積,配合gzip使用最佳,項目使用的是nginx,gzip在nginx詳細(xì)配置可參考這篇文章
AOT注意事項
由于AoT的特性,部分在JIT模式下可用的方法在AoT下是不可行或者官方不建議的,開發(fā)代碼的童鞋在aot模式下需要注意額外注意這些情況,github上8000+star的angular-starter工程總結(jié)如下(英文捉急,就不在這獻(xiàn)丑翻譯了):
- Don’t use require statements for your templates or styles, use styleUrls and templateUrls, the angular2-template-loader plugin will change it to require at build time.
- Don’t use default exports.
- Don’t use form.controls.controlName, use form.get(‘controlName’)
- Don’t use control.errors?.someError, use control.hasError(‘someError’)
- Don’t use functions in your providers, routes or declarations, export a function and then reference that function name
- @Inputs, @Outputs, View or Content Child(ren), Hostbindings, and any field you use from the template or annotate for Angular should be public
補充一些我們項目開發(fā)過程中遇到的問題,O(∩_∩)O 都是開發(fā)時代碼不規(guī)范埋下的坑:
- 定義的函數(shù)傳參必須匹配
- 等和非等判斷類型必須一致
- 未在ts定義的變量不要在html模板中使用
總結(jié)
推薦大家在dev時使用jit可以提高開發(fā)調(diào)試效率,在prod時使用aot
參考:
http://blog.mgechev.com/2016/08/14/ahead-of-time-compilation-angular-offline-precompilation/
http://blog.rangle.io/optimize-your-angular2-application-with-tree-shaking/





