從 Workbox v5 遷移至 v6

本指南著重於 Workbox 6 版中導入的破壞性變更,並舉例說明從 Workbox 5 版升級時需要進行哪些變更。

破壞性變更

workbox-core

workbox-core 中的 skipWaiting() 方法不會再新增 install 處理常式,相當於直接呼叫 self.skipWaiting()。

從現在起,請改用 self.skipWaiting(),因為 skipWaiting() 可能會在 Workbox v7 中移除。

workbox-precaching

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

workbox-routing

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

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

建構設定

workbox-build 和 workbox-cli 中 getManifest 和 injectManifest 模式的 mode 選項不應受到支援,因此已移除。這不適用於 workbox-webpack-plugin,因為該服務的 InjectManifest 外掛程式支援 mode。

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

workbox-webpack-plugin、workbox-build 或 workbox-cli 不再支援 Node.js 10 以下版本。如果您執行的 Node.js 版本低於 v8,請將執行階段更新至支援的版本。

新改良功能

workbox-strategies

Workbox v6 推出新方法,讓第三方開發人員定義自己的 Workbox 策略。這可確保第三方開發人員能以完全符合需求的方式擴充 Workbox。

新策略基礎類別

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

Strategy 基礎類別主要負責兩件事:

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

新的「處理常式」類別

我們之前有內部模組呼叫 fetchWrapper 和 cacheWrapper,顧名思義,這些模組會將各種擷取和快取 API 與掛鉤包裝到其生命週期中。這是目前允許外掛程式運作的機制,但不會向開發人員公開。

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

這個類別也讓開發人員可以新增自己的自訂生命週期回呼,這些回呼可能與其策略相關,而且可以與現有的外掛程式介面「搭配運作」。

新外掛程式生命週期狀態

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

在第 6 版中,所有外掛程式回呼也會傳遞新的 state 物件。這個狀態物件對這個特定外掛程式物件和這個特定策略叫用 (即呼叫 handle()) 而言是唯一的。這可讓開發人員編寫外掛程式,其中一個回呼可根據同一個外掛程式中另一個回呼執行的動作,有條件地執行某些動作 (例如計算執行 requestWillFetch 和 fetchDidSucceed 或 fetchDidFail 之間的時間差)。

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

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

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

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

更準確的處理常式 TypeScript 類型

各種回呼方法的 TypeScript 定義已標準化。這應該能為使用 TypeScript 並自行編寫程式碼來實作或呼叫處理常式的開發人員,提供更優質的體驗。

workbox-window

新 messageSkipWaiting() 方法

workbox-window 模組新增了 messageSkipWaiting() 方法,可簡化指示「等待中」Service Worker 啟用的程序。這項做法有以下優點:

  • 它會使用 Workbox 產生的 Service Worker 檢查的實際標準郵件內文 {type: 'SKIP_WAITING'} 呼叫 postMessage(),以觸發 skipWaiting()。
  • 它會選擇正確的「等待中」Service Worker 來發布這則訊息,即使該 Service Worker 與註冊 workbox-window 的 Service Worker 不同。

移除「外部」事件,改用 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,可實作第 6 版新增的 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 建立 Service Worker,而不是手動編寫 Service Worker,可以使用 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 提出問題,讓我們知道。