Angular 6 PWA 開發踩坑

更新中css

提示:在測試程序的時候儘可能使用Chrome的隱身模式,確保 Service Worker 不會從之前的殘留狀態中讀取數據!!html

1. PWA在Angular 6 工程上的初始化:

sudo ng new pwa新建工程以後,在工程的根目錄上運行sudo ng add @angular/pwa,此時就會自動添加Service Worker文件,Manifest.json文件和各類不一樣尺寸的icon文件。 Angular PWA中文網傳送門web

2. PWA程序的更新

app.component.ts中引入import { SwUpdate } from '@angular/service-worker';來加載SW的更新模塊,每次PWA程序有更新均可以在這裏使用SwUpdate模塊獲取更新,並使用以下代碼可實現程序的更新操做:npm

export class AppComponent {
  update: boolean;
  constructor(updates: SwUpdate, private data: DataService) {
    updates.available.subscribe( event => {
      this.update = true;
      updates.activateUpdate().then(() =>
        document.location.reload()
      );
      }
    );
  }
  title = 'PWA';
}
複製代碼

SwUpdate文檔傳送門json

而後在html中使用一個*ngIf來判斷是否更新,(是則顯示text,不是則不顯示):api

<span *ngIf="update">There's an update associated with your progressive web application!</span>
複製代碼

每次更新了程序都要從新build production程序,在根目錄上運行sudo ng build --prod,而後進入cd dist/PWA,最後運行http-server -o在服務器上運行更新後的程序。瀏覽器

因爲 ng serveService Worker 無效,因此必須用一個獨立的 HTTP 服務器在本地測試項目。 可使用任何 HTTP 服務器,我使用的是來自 npm 中的 http-server 包。固然也能夠自定義端口以防止port衝突:緩存

http-server -p 8080 -c-1 dist/<project-name>
複製代碼

注意: 若是想按期更新PWA,也就是使用interval建立一個週期輪詢方法,須要先讓應用註冊Aervice worker的進程進入穩定狀態,再讓它開始執行輪詢的過程,若是不斷輪詢更新(好比調用 interval())將阻止應用程序達到穩定態,也就永遠不會往瀏覽器中註冊 ServiceWorker 腳本。另外:應用中所執行的各類輪詢都會阻止它達到穩定態服務器

constructor(appRef: ApplicationRef, updates: SwUpdate) {
        // Allow the app to stabilize first, before starting polling for updates with `interval()`.
        const appIsStable$ = appRef.isStable.pipe(first(isStable => isStable === true));
        const everySixHours$ = interval(6 * 60 * 60 * 1000);
        const everySixHoursOnceAppIsStable$ = concat(appIsStable$, everySixHours$);
        everySixHoursOnceAppIsStable$.subscribe(() => updates.checkForUpdate());
  }
複製代碼

因此對於自動更新模塊的使用總結:網絡

constructor(appRef: ApplicationRef, updates: SwUpdate, private data: DataService) {
    const appIsStable$ = appRef.isStable.pipe(first(isStable => isStable === true));
    const everySixHours$ = interval(6 * 1000);
    const everySixHoursOnceAppIsStable$ = concat(appIsStable$, everySixHours$);
    everySixHoursOnceAppIsStable$.subscribe(() => {
      updates.checkForUpdate();
      // console.log('check update in Service Worker');
    });
    updates.available.subscribe(event => {
      console.log('gotta new version here', event.available);
      updates.activateUpdate().then(() => document.location.reload());
    });
  }
複製代碼

每6妙檢測一次更新版本,若是沒有updates.activateUpdate().then(() => document.location.reload());則只是在檢測到新版本時候提醒並不刷新並更新程序。 測試的時候須要從新ng build --prod而後http-server -p 8080 -c-1 dist/PWA從新運行http服務器,這時候在原來的頁面上的console上就會發現出現了新版本的提醒。

(其實每次運行build命令都會出現版本更新不管是否更改代碼,當應用的一個新的構建發佈時,Service Worker 就把它看作此應用的一個新版本,版本是由 ngsw.json 文件的內容決定的,包含了全部已知內容的哈希值。 若是任何一個被緩存的文件發生了變化,則該文件的哈希也將在ngsw.json中隨之變化,從而致使 Angular Service Worker 將這個活動文件的集合視爲一個新版本)

3. 如何緩存文件以及API的地址以及其餘項目?

全在nsgw-config.json文件中定義PWA緩存,好比想緩存google的Montserrat字體和API地址,該文件中全部的代碼形式都是glob格式,也就是:

  • ' ** ' 匹配 0 到多段路徑
  • ' * ' 匹配 0 個或更多個除 / 以外的字符
  • ? 匹配除 / 以外的一個字符
  • ! 前綴表示該模式是反的,也就是說只包含與該模式不匹配的文件

好比:

  • /**/*.html 指定全部 HTML 文件
  • /*.html 僅指定根目錄下的 HTML 文件
  • !/**/*.map 排除了全部源碼映射文件

在實際代碼中這樣作:

<link href="https://fonts.googleapis.com/css?family=Montserrat" rel="stylesheet">
複製代碼

在已經被建立的assetGroups中添加:

"urls": [
    "https://fonts.googleapis.com/**"
  ]
複製代碼

AssetGroup遵循的TypeScript接口規則爲:

interface AssetGroup {
  name: string;
  installMode?: 'prefetch' | 'lazy';
  // prefetch 告訴 Angular Service Worker 在緩存當前版本的應用時要獲取每個列出的資源。 這是個帶寬密集型的模式,但能夠確保這些資源在請求時可用,即便瀏覽器正處於離線狀態
  // lazy 不會預先緩存任何資源。相反,Angular Service Worker 只會緩存它收到請求的資源。 這是一種按需緩存模式。永遠不會請求的資源也永遠不會被緩存。 這對於像爲不一樣分辨率提供的圖片之類的資源頗有用,那樣 Service Worker 就只會爲特定的屏幕和設備方向緩存正確的資源。
  updateMode?: 'prefetch' | 'lazy';
  // prefetch 會告訴 Service Worker 當即下載並緩存更新過的資源
  // lazy 告訴 Service Worker 不要緩存這些資源,而是先把它們看做未被請求的,等到它們再次被請求時才進行更新。 
  lazy 這個 updateMode 只有在 installMode 也一樣是 lazy 時纔有效。
  resources: {
    files?: string[];
    /** @deprecated As of v6 `versionedFiles` and `files` options have the same behavior. Use `files` instead. */
    versionedFiles?: string[];
    urls?: string[];
  };
}
複製代碼

在下方建立dataGroups緩存API地址:

"dataGroups": [
    {
      "name": "jokes-api",
      "urls": [
        "https://api.chucknorris.io/jokes/random"
      ],
      "cacheConfig": {
        "strategy": "freshness",
        "maxSize": 20,
        "maxAge": "1h",
        "timeout": "5s"
      }
    }
  ]
複製代碼

dataGroups的配置遵循下面的接口:

export interface DataGroup {
  name: string;
  urls: string[];
  version?: number;
  cacheConfig: {
    maxSize: number;
    maxAge: string;
    timeout?: string;
    strategy?: 'freshness' | 'performance';
  };
}
複製代碼

其中的緩存設置中的幾個項目分別是:

  • "strategy" :
    1. performance,默認值,爲儘快給出響應而優化。若是緩存中存在某個資源,則使用這個緩存版本。 它容許資源有必定的陳舊性(取決於 maxAge)以換取更好的性能。適用於那些不常常改變的資源,例如用戶頭像。
    2. freshness 爲數據的即時性而優化,優先從網絡獲取請求的數據。只有當網絡超時時,請求才會根據 timeout 的設置回退到緩存中。這對於那些頻繁變化的資源頗有用,例如帳戶餘額。
  • "maxSize" : (必需)緩存的最大條目數或響應數。開放式緩存能夠無限增加,並最終超過存儲配額,建議適時清理。
  • "maxAge" : d(必需)maxAge 參數表示在響應因失效而要清除以前容許在緩存中留存的時間。(d:天數,h:小時數,m:分鐘數,s:秒數,u:微秒數)
  • "timeout" : 這個表示持續時間的字符串用於指定網絡超時時間。 若是配置了它,Angular Service Worker 在開始使用緩存以前就會先等待網絡給出響應,這個等待時間就是網絡超時時間。
相關文章
相關標籤/搜索