iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 25
1

關於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命令中:

ng new my-project --service-worker

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

  • 步驟1:添加service worker package

    yarn add @angular/service-worker
    
  • 步驟2:在CLI中啟用service worker

    ng set apps.0.serviceWorker=true
    
  • 步驟3:導入並註冊service worker 在src/app/app.module.ts

    import { ServiceWorkerModule } from '@angular/service-worker';
    import { environment } from '../environments/environment';
    

    app.module.ts

        @NgModule({
      declarations: [
        AppComponent
      ],
      imports: [
        BrowserModule,
        ServiceWorkerModule.register('/ngsw-worker.js', {enabled: environment.production})//註冊ServiceWorker腳本的名稱
      ],
      providers: [
        CheckForUpdateService,
        LogUpdateService,
        PromptUpdateService,
      ],
      bootstrap: [AppComponent]
    })
    export class AppModule { }
    
  • 步驟4:創建配置文件ngsw-config.json 大多數src/ngsw-config.json合理的默認值如下:

    {
      "index": "/index.html",
      "assetGroups": [{
        "name": "app",
        "installMode": "prefetch",
        "resources": {
          "files": [
            "/favicon.ico",
            "/index.html"
          ],
          "versionedFiles": [
            "/*.bundle.css",
            "/*.bundle.js",
            "/*.chunk.js"
          ]
        }
      }, {
        "name": "assets",
        "installMode": "lazy",
        "updateMode": "prefetch",
        "resources": {
          "files": [
            "/assets/**"
          ]
        }
      }]
    }
    
  • 第5步:構建項目

    ng build --prod
    

觀察Service worker的運行

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

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

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

SwUpdate service

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

@Injectable()
export class LogUpdateService {

  constructor(updates: SwUpdate) {
    updates.available.subscribe(event => {
      console.log('current version is', event.current);
      console.log('available version is', event.available);
    });
    updates.activated.subscribe(event => {
      console.log('old version was', event.previous);
      console.log('new version is', event.current);
    });
  }
}

檢查更新的方式

import { interval } from 'rxjs/observable/interval';

@Injectable()
export class CheckForUpdateService {

  constructor(updates: SwUpdate) {
    interval(6 * 60 * 60).subscribe(() => updates.checkForUpdate());
  }
}

強制更新資料

@Injectable()
export class PromptUpdateService {

  constructor(updates: SwUpdate) {
    updates.available.subscribe(event => {
      if (promptUser(event)) {
        updates.activateUpdate().then(() => document.location.reload());
      }
    });
  }
}

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的範例:

NGSW Debug Info:
//這邊是指service worker的Driver狀態,有三種值:NORMAL(正常),EXISTING_CLIENTS_ONLY(舊的快取可安全使用),SAFE_MODE(版存資料失效,所有資料都會由網路提供)
Driver state: NORMAL ((nominal))
//最新清單的SHA hash
Latest manifest hash: eea7f5f464f90789b621170af5a569d6be077e5c
//上次更新檢查 
Last update check: never 
//版本資訊
=== Version eea7f5f464f90789b621170af5a569d6be077e5c ===

Clients: 7b79a015-69af-4d3d-9ae6-95ba90c79486, 5bc08295-aaf2-42f3-a4cc-9e4ef9100f65
//空閒任務隊列
=== Idle Task Queue ===
Last update tick: 1s496u
Last update run: never
Task queue:
 * init post-load (update, cleanup)
//調試日誌
Debug log:

配置文件格式介紹

詳細說明請見Service Worker Configuration

參考資料


上一篇
[技術支援-2] 讓IDE支援Angular Language Service
下一篇
[技術支援-4] Angular Universal
系列文
用30天深入Angular 5的世界31

1 則留言

1
Blackie Tsai
iT邦新手 5 級 ‧ 2018-01-14 09:49:49

Hihi,

Service worker 不是angular的新觀念歐,相反的他比Angular 4/5甚至2更早被提出與實作。

整體上此技術與離線web app 有關,但是從好幾年前PWA web所衍生出來的話題。

基本上不用angular也可以用service worker. 不過現在主流框架可能都會在預設的專案內幫你添加好。

我去年另外寫的一篇可以分享給你

https://blackie1019.github.io/2017/08/01/Using-Service-Worker-to-Optimize-Web-Site-Performance/

謝謝分享!

我要留言

立即登入留言