從 Workbox v5 遷移至 v6

本指南著重於說明 Workbox 6.0 中引入的破壞性變更,並提供從 Workbox 5.0 升級時需要進行的變更範例。

破壞性變更

workbox-core

workbox-core 中的 skipWaiting() 方法將不再加入 install 處理常式,且等同於只呼叫 self.skipWaiting()

skipWaiting() 可能會在 Workbox v7 中移除,因此建議您從現在起改用 self.skipWaiting()

workbox-precaching

  • 與 HTTP 重新導向相對應的網址,其跨來源 HTML 文件無法再用於滿足 workbox-precaching 的導覽要求。這種情況通常不常見。
  • workbox-precaching 在查詢特定要求的預先快取回應時,現在會忽略 fbclid 網址查詢參數。
  • PrecacheController 建構函式現在會使用具有特定屬性的物件做為參數,而非字串。這個物件支援以下屬性:cacheName (與在 v5 中傳入建構函式的字串具有相同用途)、plugins (取代 v5 中的 addPlugins() 方法) 和 fallbackToNetwork (取代傳入 createHandler() 和 v5 中的 `createHandlerBoundToURL() 的類似選項)。
  • PrecacheControllerinstall()activate() 方法現在只會採用一個參數,且應分別設為對應的 InstallEventActivateEvent
  • addRoute() 方法已從 PrecacheController 中移除。您可以改用新的 PrecacheRoute 類別建立路線,然後再註冊。
  • precacheAndRoute() 方法已從 PrecacheController 中移除。(它仍會以 workbox-precaching 模組匯出的靜態輔助程式方法形式存在)。這是因為 PrecacheRoute 可做為替代方案。
  • createMatchCalback() 方法已從 PrecacheController 中移除。您可以改用新的 PrecacheRoute
  • createHandler() 方法已從 PrecacheController 中移除。您可以改用 PrecacheController 物件的 strategy 屬性來處理要求。
  • createHandler() 靜態匯出項目已從 workbox-precaching 模組中移除。開發人員應改為建構 PrecacheController 例項,並使用其 strategy 屬性。
  • 使用 precacheAndRoute() 註冊的路徑現在是「實際」路徑,會在背景中使用 workbox-routingRouter 類別。如果您交錯 registerRoute()precacheAndRoute() 的呼叫,路徑的評估順序可能會有所不同。

workbox-routing

setDefaultHandler() 方法現在會使用選用的第二個參數,對應至所套用的 HTTP 方法,預設為 'GET'

  • 如果您使用 setDefaultHandler(),且所有要求都是 GET,則不需要進行任何變更。
  • 如果您有任何非 GET 的請求 (POSTPUT 等),setDefaultHandler() 將不再導致這些要求相符。

版本設定

workbox-buildworkbox-cligetManifestinjectManifest 模式的 mode 選項並未納入支援範圍,因此已遭移除。這項規定不適用於 workbox-webpack-plugin,因為其 InjectManifest 外掛程式支援 mode

建構工具需要 Node.js 10 以上版本

workbox-webpack-pluginworkbox-buildworkbox-cli 不再支援 v10 之前的 Node.js 版本。如果您執行的 Node.js 版本低於 v8,請將執行階段更新至支援的版本

新功能改善

workbox-strategies

Workbox 6.0 推出了第三方開發人員定義自身 Workbox 策略的新方法。這可確保第三方開發人員能夠根據自身需求,擴充 Workbox 的功能。

新的 Strategy 基礎類別

在 6.0 版中,所有 Workbox 策略類別都必須擴充新的 Strategy 基礎類別。我們已重新編寫所有內建策略,以便支援這項功能。

Strategy 基本類別負責兩項主要工作:

  • 叫用所有策略處理常見的外掛程式生命週期回呼 (例如開始、回應和結束時)。
  • 建立「處理程序」例項,可管理策略處理的每項個別要求狀態。

新的「handler」類別

我們先前有內部模組呼叫 fetchWrappercacheWrapper,這兩者 (如其名稱所示) 會將各種擷取和快取 API 包裝在生命週期中。這是目前允許外掛程式運作的機制,但不會向開發人員公開。

新的「處理程序」類別 StrategyHandler 會公開這些方法,讓自訂策略呼叫 fetch()cacheMatch(),並自動叫用已新增至策略例項的任何外掛程式。

這個類別還可讓開發人員新增自訂的生命週期回呼,這些回呼可能會針對特定策略進行設定,並且可與現有的外掛程式介面「直接運作」。

新的外掛程式生命週期狀態

在 Workbox v5 中,外掛程式是無狀態的。也就是說,如果 /index.html 的要求同時觸發 requestWillFetchcachedResponseWillBeUsed 回呼,這兩個回呼就無法互相通訊,甚至無法得知是由同一個要求觸發。

在 v6 中,所有外掛程式回呼也會傳遞新的 state 物件。這個狀態物件將是此特定外掛程式物件和此特定策略叫用 (即對 handle() 的呼叫) 專屬。這可讓開發人員編寫外掛程式,讓一個回呼可根據同一個外掛程式中的另一個回呼所執行的動作,有條件地執行某些動作 (例如,計算執行 requestWillFetchfetchDidSucceedfetchDidFail 之間的時間差異)。

新的外掛程式生命週期回呼

我們新增了新的外掛程式生命週期回呼,讓開發人員充分利用外掛程式生命週期狀態:

  • handlerWillStart:在任何處理常式邏輯開始執行前呼叫。這個回呼可用於設定初始處理常態 (例如記錄開始時間)。
  • handlerWillRespond:在策略 handle() 方法傳回回應前呼叫。這個回呼可用於修改回應,然後再傳回至路徑處理常式或其他自訂邏輯。
  • handlerDidRespond:在策略的 handle() 方法傳回回應後呼叫。這個回呼可用於記錄任何最終回應詳細資料,例如其他外掛程式所做的變更。
  • handlerDidComplete:在從這個策略的叫用新增至事件的所有延長生命週期承諾已完成後呼叫。這個回呼可用於回報任何需要等待處理程序完成才能計算的資料 (例如快取命中狀態、快取延遲、網路延遲)。
  • handlerDidError:如果處理程序無法從任何來源提供有效回應,就會呼叫此方法。這個回呼可用於提供「備用」內容,做為網路錯誤的替代方案。

實作自訂策略的開發人員不必擔心要自行叫用這些回呼,因為這項工作會由新的 Strategy 基礎類別處理。

更精確的處理常式 TypeScript 類型

各種回呼方法的 TypeScript 定義已完成規格化。這項功能應可為使用 TypeScript 的開發人員帶來更優質的體驗,讓他們自行編寫程式碼來實作或呼叫處理常式。

workbox-window

新 messageSkipWaiting() 方法

messageSkipWaiting() 這個新方法已新增至 workbox-window 模組,簡化通知「等待中」服務工作程式啟動程序的過程。這項功能帶來以下改善:

  • 這個函式會使用實際的標準訊息主體 {type: 'SKIP_WAITING'} 呼叫 postMessage(),Workbox 產生的服務 worker 會檢查 {type: 'SKIP_WAITING'},以觸發 skipWaiting()
  • 它會選擇正確的「等待中」服務工作站,用於發布這則訊息,即使該服務工作站與 workbox-window 註冊的服務工作站不同也一樣。

移除「external」事件,改用 isExternal 屬性

workbox-window 中的所有「外部」事件都已移除,並以「一般」事件取代,且 isExternal 屬性設為 true。這樣一來,有需要的開發人員仍可偵測到差異,而不需要知道的開發人員則可忽略該屬性。

清理「為使用者提供網頁重新載入功能」的最佳化方

由於上述兩項異動,「為使用者提供網頁重新載入」方程式可簡化為:

// v6:
<script type="module">
  import {Workbox} from 'https://storage.googleapis.com/workbox-cdn/releases/6.0.0-alpha.1/workbox-window.prod.mjs';

  if ('serviceWorker' in navigator) {
    const wb = new Workbox('/sw.js');

    const showSkipWaitingPrompt = () => {
      // This assumes a hypothetical createUIPrompt() method with
      // onAccept and onReject callbacks:
      const prompt = createUIPrompt({
        onAccept: () => {
          wb.addEventListener('controlling', () => {
            window.location.reload();
          });

          // This will postMessage() to the waiting service worker.
          wb.messageSkipWaiting();
        },

        onReject: () => {
          prompt.dismiss();
        },
      });
    };

    // Listening for externalwaiting is no longer needed.
    wb.addEventListener('waiting', showSkipWaitingPrompt);
    wb.register();
  }
</script>

workbox-routing

新的布林參數 sameOrigin 會傳遞至 workbox-routing 中使用的 matchCallback 函式。如果要求是針對相同來源網址,則設為 true;否則設為 false。

這麼做可簡化一些常見的模板:

// In v5:
registerRoute(
  ({url}) =>
    url.origin === self.location.origin && url.pathname.endsWith('.png'),
  new StaleWhileRevalidate({cacheName: 'local-png'})
);

// In v6:
registerRoute(
  ({sameOrigin, url}) => sameOrigin && url.pathname.endsWith('.png'),
  new StaleWhileRevalidate({cacheName: 'local-png'})
);

workbox-expiration 中的 matchOptions

您現在可以在 workbox-expiration 中設定 matchOptions,系統會將其傳遞為 CacheQueryOptions,並傳送至基礎 cache.delete() 呼叫。(大多數開發人員不需要這麼做)。

workbox-precaching

使用 workbox-strategies

workbox-precaching 已重寫,以便使用 workbox-strategies 做為基礎。這項變更不應導致任何重大變更,且應可改善兩個模組存取網路和快取的方式,讓兩者在長期上保持一致。

預先快取現在會逐一處理項目,而非大量處理

workbox-precaching 已更新,因此系統只會一次要求及快取預先快取資訊清單中的一個項目,而不會嘗試一次要求及快取所有項目 (讓瀏覽器自行決定如何節流)。

這麼做可降低預先快取時發生 net::ERR_INSUFFICIENT_RESOURCES 錯誤的可能性,並減少預先快取與網頁應用程式同時提出的請求之間的頻寬爭用情形。

PrecacheFallbackPlugin 可讓您更輕鬆地使用離線備用機制

workbox-precaching 現在包含 PrecacheFallbackPlugin,可實作 v6 中新增的 handlerDidError 生命週期方法。

如此一來,如果無法取得回應,您就能輕鬆將已快取的網址指定為特定策略的「備用」網址。外掛程式會負責為預先快取的網址正確建構快取鍵,包括任何所需的修訂參數。

以下是使用此方法的範例,當 NetworkOnly 策略無法為導覽要求產生回應時,您可以使用預先快取的 /offline.html 進行回應,也就是顯示自訂的離線 HTML 頁面:

import {PrecacheFallbackPlugin, precacheAndRoute} from 'workbox-precaching';
import {registerRoute} from 'workbox-routing';
import {NetworkOnly} from 'workbox-strategies';

// Ensure that /offline.html is part of your precache manifest!
precacheAndRoute(self.__WB_MANIFEST);

registerRoute(
  ({request}) => request.mode === 'navigate',
  new NetworkOnly({
    plugins: [
      new PrecacheFallbackPlugin({
        fallbackURL: '/offline.html',
      }),
    ],
  })
);

precacheFallback 在執行階段快取

如果您使用 generateSW 為您建立服務工作者,而不是手動編寫服務工作者,您可以使用 runtimeCaching 中的新 precacheFallback 設定選項來完成相同的工作:

{
  // ... other generateSW config options...
  runtimeCaching: [{
    urlPattern: ({request}) => request.mode === 'navigate',
    handler: 'NetworkOnly',
    options: {
      precacheFallback: {
        // This URL needs to be included in your precache manifest.
        fallbackURL: '/offline.html',
      },
    },
  }],
}

取得協助

我們預期大部分的遷移作業都會很簡單。如果您遇到本指南未涵蓋的問題,請在 GitHub 上提出問題,讓我們瞭解實際狀況。