[技術支援-5] 佈署方式JIT及AOT介紹

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

如果我們使用--prod預設也會是aot輸出。

用AOT編譯的程式編寫限制

如果使用AOT預編譯,在撰寫angular的metadata要注意下面幾點:

不支援function expression

不支援Arrow functions

像下面這種設定方法在AOT是不被支援的

需改成這樣:

在元數據內單獨使用常數

因為常數是在編譯時就編譯進JS裡,如下面的寫法會造成AOT在編譯時遺失template常數的值:

我們可以改用下面這種寫法

或將常數放至一個運算表達式內:

裝飾和數據綁定的類成員必須公開

在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

參考資料

[技術支援-4] Angular Universal

什麼是Angular Universal

下面是一段截錄於https://itw01.com/G3MBE3P.html對Angular Universal目的的說明

雖然Angular是一種構建Web應用的強大方式,但是長期以來,開發人員都知道它在SEO和可訪問性方面的限制。當然,Google的爬蟲能夠執行JavaScript,但是它並不是唯一的爬蟲方案。例如,在將一個連結提交給Slack之後,它的爬蟲會抓取一個預覽,但是並不會執行JavaScript,所以原始的Angular HTML模板將會顯示在預覽之中。爲了消除這種現象所產生的問題,Jeff Whelpley和Patrick Stapleton開發了Angular Universal,它允許在服務端進行渲染。

從上面的文字可以了解,Angular Universal可以在server side預先對網頁模版做處理,變成一個有資料的靜態頁面。可以在使用者要求資料的當下產生靜態頁面,也可以事先產生好靜態檔案以供未來使用。

Angular Universal的主要目的有以下三個

  • 方便網路爬蟲(SEO)
  • 提高在手機裝置和效能較差的設備上的性能表現
  • 快速顯示第一頁

Google,Bing,Facebook,Twitter和其他社交媒體網站都依靠網路爬蟲來為網站編索引,並在搜索內容。Angular Universal可以生成應用程序的靜態版本,無需JavaScript即可輕鬆搜索,鏈接和導航。這也使網站預覽可用,因為每個URL返回一個完全呈現的頁面。

啟用網頁抓取工具通常被稱為 搜索引擎優化(SEO)。

安裝Angular Universal所需工具

  • @angular/platform-server – 通用服務器端組件。
  • @nguniversal/module-map-ngfactory-loader – 用於在服務器渲染的上下文中處理延遲加載。
  • @nguniversal/express-engine – 通用應用程序的快速引擎。
  • ts-loader – 傳輸服務器應用程序

使用下面指令安裝上面四個package

更新 AppModule 模組

修正預設AppModuleBrowserModule的匯入方式

根據使用者的瀏覽器來決定是否使用SSR(server-side rendering)

撰寫SSR Server的程式碼

src/app/app.server.module.ts

在這邊使用Express framework來做server,利用Universal的renderModuleFactory功能來輸出靜態檔案

下面是Express的Server檔案內容server.ts

Universal的設定檔

src/tsconfig.server.json的內容如下:

BUILD出檔案

參考資料

[技術支援-3] Service worker離線支援

關於Service worker

Angular在第5版新推出了支援Service worker的功能,主要是可以讓Angular更能符合PWA的概念

所謂PWA(Progressive Web App)是希望能夠讓Web application盡可能的在各種環境(網路環境、手機作業系統等)下都能順暢且不減功能性的運作。
例如要可以支援離線功能,在使用 App 收信、寫信、刪除信件等動作,都需要將結果丟回伺服器儲存,但在某些環境下並無法一直使用網路連線,因此必須使用一種機制,讓我們仍能順暢的使用這些功能,待網路正常連線,再將剛才所執行的一切動作反應回伺服器
而Service Worker可以讓Web application做到上面這樣的事情。

使用Service worker所需環境

要使用Angular Service worker,您必須具有以下Angular和CLI版本:

  • Angular 5.0.0或更高版本。
  • Angular CLI 1.6.0或更高版本。

Web application必須在支援Service worker的Web瀏覽器中運行。
目前支持最新版本的Chrome和Firefox。其他瀏覽器的支援狀況如下圖(連結):

Service Worker 的生命週期

圖片來源:Browser push notifications using JavaScript

在創建新的應用程序時使用Service worker

--service-worker標誌添加到ng new命令中:

在現有的應用程序加入Service worker

  • 步驟1:添加service worker package
  • 步驟2:在CLI中啟用service worker
  • 步驟3:導入並註冊service worker
    src/app/app.module.ts

    app.module.ts
  • 步驟4:創建配置文件ngsw-config.json
    大多數src/ngsw-config.json合理的默認值如下:
  • 第5步:構建項目

觀察Service worker的運行

可以使用Chrome Debug Tool,設置瀏覽器狀態為離線

從Network的資料會可以看到現在HTTP資料的來源是來自於service worker

這個面版可以觀察Service worker的運行狀況

SwUpdate service

下面是利用SwUpdate來取得現有可用及被啟用的notified的方式

檢查更新的方式

強制更新資料

Service worker和快取緩存離線資料

我們可以將Service worker想像成像瀏覽器快取或者CDN edge一樣,都是會將網頁資料暫存起來。只是Service worker是將資料存在瀏覽器上。

透過設置src/ngsw-config.json來設定版本資訊,被分組到同一個版本的文件通常包括HTML,JS和CSS,這些文件的完整性非常重要,因為JS和CSS常常會互相引用並彼此依賴。
例如在index.html裡可能引用了bundle.js並呼叫了它的方法startApp(),如果某次改版我們將startApp()改名為runApp(),但是在index.html裡若是舊的版本,依舊呼叫startApp(),就會造成執行上的錯誤。

因此快取設定資料的完整性和版本的一致性非常的重要,可以確保ANGULAR在離線執行時可以正常運作。

每次使用者打開或更新網頁時,Angular service worker都會透過ngsw.json的更新來檢查應用程序的更新。如果有發現有更新的頁面,將會自動下載並緩存,在下次載入網頁時提供。

Debugging the Angular service worker

有關於service worker的debug資訊都在ngsw/底下,公開的網址為ngsw/state

下面是一個ngsw/state的範例:

配置文件格式介紹

詳細說明請見Service Worker Configuration

參考資料