從 Workbox v4 遷移至 v5

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

破壞性變更

重新命名外掛程式類別

許多 Workbox 4.x 套件都包含名為 Plugin 的類別。在 v5 中,這些類別已重新命名,以便遵循套件 ID + Plugin 的模式:

  • BackgroundSyncPlugin
  • BroadcastUpdatePlugin
  • CacheableResponsePlugin
  • ExpirationPlugin
  • RangeRequestsPlugin

無論您是透過模組匯入作業或透過 workbox.* 命名空間使用類別,都可以使用這個重新命名。

預設友善快取資訊清單替換點

先前在「注入資訊清單」模式下使用其中一個建構工具時,系統會檢查來源服務工作者檔案是否有 precacheAndRoute([]),並使用空白陣列 [] 做為預先快取資訊清單注入點的預留位置。

在 Workbox v5 中,取代邏輯已變更,現在預設會使用 self.__WB_MANIFEST 做為插入點。

// v4:
precacheAndRoute([]);

// v5:
precacheAndRoute(self.__WB_MANIFEST);

這篇討論串所述,我們認為這項異動可提供更簡單的使用體驗,同時讓開發人員更能控管如何在自訂服務工作程式程式碼中使用插入的資訊清單。如有需要,您可以透過 injectionPoint 設定選項變更這個替換字串。

blacklistwhitelist 先前支援的導覽路徑已重新命名為 denylistallowlist

workbox-routing 先前支援 registerNavigationRoute() 方法,其實際上會執行以下兩項作業:

  1. 偵測特定 fetch 事件是否有 'navigate'mode
  2. 如果是,則會使用先前快取的硬式編碼網址內容回應該要求,無論導向的網址為何。

這是實作 App Shell 架構時常用的模式。

第二個步驟是從快取讀取資料來產生回應,超出我們視為 workbox-routing 的責任。我們認為這項功能應透過新方法 createHandlerBoundToURL() 納入 workbox-precaching。這個新方法可與 workbox-routing 中現有的 NavigationRoute 類別搭配使用,以完成相同的邏輯。

如果您在某個建構工具的「產生 SW」模式中使用 navigateFallback 選項,系統就會自動切換。如果您先前已設定 navigateFallbackBlacklistnavigateFallbackWhitelist 選項,請分別將這些選項變更為 navigateFallbackDenylistnavigateFallbackAllowlist

如果您使用「插入資訊清單」模式,或您只是自行編寫 Service Worker,而 Workbox v4 Service Worker 會直接呼叫 registerNavigationRoute(),這時必須修改程式碼才能獲得對等的行為。

// v4:
import {getCacheKeyForURL} from 'workbox-precaching';
import {registerNavigationRoute} from 'workbox-routing';

const appShellCacheKey = getCacheKeyForURL('/app-shell.html');
registerNavigationRoute(appShellCacheKey, {
  whitelist: [...],
  blacklist: [...],
});

// v5:
import {createHandlerBoundToURL} from 'workbox-precaching';
import {NavigationRoute, registerRoute} from 'workbox-routing';

const handler = createHandlerBoundToURL('/app-shell.html');
const navigationRoute = new NavigationRoute(handler, {
  allowlist: [...],
  denylist: [...],
});
registerRoute(navigationRoute);

您不再需要呼叫 getCacheKeyForURL(),因為 createHandlerBoundToURL() 會為您處理這項作業。

從 workbox-strategies 移除 makeRequest()

呼叫 makeRequest() 大致等同於在其中一個 workbox-strategy 類別上呼叫 handle()。這兩種方法的差異非常微小,不合邏輯。呼叫 makeRequest() 的開發人員應可切換為使用 handle(),而無須進行任何其他變更:

// v4:
const strategy = new StaleWhileRevalidate({...});
const response = await strategy.makeRequest({event, request});

// v5:
const strategy = new StaleWhileRevalidate({...});
const response = await strategy.handle({event, request});

在 5 版中,handle() 會將 request 視為必要參數,且不會改回使用 event.request。呼叫 handle() 時,請務必傳入有效的要求。

workbox-broadcast-update 一律使用 postMessage()

在 v4 中,workbox-broadcast-update 程式庫會在支援的情況下預設使用 Broadcast Channel API 傳送訊息,並且只在不支援 Broadcast Channel 時改用 postMessage()

我們瞭解必須監聽兩個潛在的傳入訊息來源,導致用戶端程式碼的編寫過程過於複雜。此外,在部分瀏覽器中,針對傳送至用戶端頁面的 Service Worker 的 postMessage() 呼叫會自動緩衝處理,直到 message 事件監聽器設定為止。Broadcast Channel API 不會有緩衝處理,而如果在用戶端頁面準備好接收訊息之前傳送,則廣播訊息只會遭到捨棄。

基於這些原因,我們已將 workbox-broadcast-update 變更為在 v5 中一律使用 postMessage()。訊息會逐一傳送至目前 Service Worker 範圍內的所有用戶端頁面。

為了因應這項新行為,您可以移除建立 BroadcastChannel 例項的用戶端網頁中的任何程式碼,然後改在 navigator.serviceWorker 上設定 message 事件監聽器:

// v4:
const updatesChannel = new BroadcastChannel('api-updates');
updatesChannel.addEventListener('message', event => {
  const {cacheName, updatedUrl} = event.data.payload;
  // ... your code here ...
});

// v5:
// This listener should be added as early as possible in your page's lifespan
// to ensure that messages are properly buffered.
navigator.serviceWorker.addEventListener('message', event => {
  // Optional: ensure the message came from workbox-broadcast-update
  if (event.meta === 'workbox-broadcast-update') {
    const {cacheName, updatedUrl} = event.data.payload;
    // ... your code here ...
  }
});

workbox-window 使用者不必進行任何變更,因為我們更新了內部邏輯,以便監聽 postMessage() 呼叫。

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

workbox-webpack-pluginworkbox-buildworkbox-cli 不再支援第 8 版之前的 Node.js 版本。如果您執行的是 8 以下版本的 Node.js,請將執行階段更新至支援的版本

Workbox-webpack-plugin 需要 webpack v4 以上版本

如果您使用的是 workbox-webpack-plugin,請更新 webpack 設定,使其至少使用 webpack v4。

建構工具選項改版

不再支援許多 workbox-buildworkbox-cliworkbox-webpack-plugin 設定參數。舉例來說,generateSW 會一律為您建立本機 Workbox 執行階段套件,因此 importWorkboxFrom 選項已無意義。

如需支援的選項清單,請參閱相關工具的說明文件。

從 workbox-build 中移除 generateSWString

已從 workbox-build 中移除generateSWString模式。我們預期這項異動的影響會很小,因為 workbox-webpack-plugin 主要在內部使用這項功能。

選擇性變更

使用模組匯入

雖然這項變更 (a) 屬於選用,且 (b) 在使用 Workbox 第 4 版時,技術上是可行的,但我們預期在改用第 5 版時,最大的變更是您可以透過匯入 Workbox 模組,自行建立已組合的服務 worker。這種做法是呼叫服務工作站頂端的 importScripts('/path/to/workbox-sw.js') 的替代方案,以及透過 workbox.* 命名空間使用 Workbox。

如果您在「產生 SW」中正在使用其中一項建構工具 (workbox-webpack-pluginworkbox-buildworkbox-cli)模式,系統就會自動套用這項變更。所有這些工具都會輸出 Workbox 執行階段的本機自訂套件,以及實作服務工作站邏輯所需的實際程式碼。在這個情境中,不再需要任何依賴 workbox-sw 或 Workbox 的 CDN 副本。視 inlineWorkboxRuntime 設定的值而定,Workbox 執行階段會分割為個別檔案,並與服務工作站一併部署 (設定為 false 時,這是預設值),或是與服務工作站邏輯一併內嵌 (設定為 true 時)。

如果在「插入資訊清單」中使用建構工具模式,或者您完全沒有使用 Workbox 的建構工具時,可以參閱現有的搭配 Workbox 使用 Bundlers (webpack/Rollup) 指南,進一步瞭解如何建立自己的 Workbox 執行階段套件。

我們以模組匯入語法為例撰寫第 5 版說明文件和範例,但 Workbox v5 會繼續支援 workbox.* 命名空間。

讀取友善快取回應

部分開發人員需要直接從快取讀取預先快取的回應,而非透過 precacheAndRoute() 方法以隱含方式使用回應。第 4 版中的常見模式如下:先取得友善快取資源目前版本的專屬快取金鑰,然後將該金鑰與預先快取的快取名稱一併傳入 caches.match(),以取得 Response

為簡化這項程序,第 5 版的 workbox-precaching 支援新的等效方法 matchPrecache()

// v4:
import {cacheNames} from 'workbox-core';
import {getCacheKeyForURL} from 'workbox-precaching';

const cachedResponse = await caches.match(
  getCacheKeyForURL(`/somethingPrecached`),
  {
    cacheName: cacheNames.precache,
  }
);

// v5:
import {matchPrecache} from 'workbox-precaching';

const cachedResponse = await matchPrecache(`/somethingPrecached`);

採用 TypeScript

在 v5 中,Workbox 執行階段程式庫是以 TypeScript 編寫。針對尚未採用 TypeScript 的開發人員,我們會繼續發布轉譯的 JavaScript 模組和套件,但如果您使用的是 TypeScript,就應該直接在 Workbox 專案中取得準確且最新的類型資訊。

遷移範例

這項提交說明了相當複雜的遷移作業,並附上內嵌註解。該工具會使用「綜覽」來納入 自訂 Workbox 執行階段,而不是從 CDN 載入執行階段。

雖然這裡沒有涵蓋所有重大變更,但以下是將一個服務工作者檔案從 v4 升級至 v5 的前後比較,包括切換至 TypeScript。

取得協助

我們預期大部分遷移作業都會很簡單。如果您遇到本指南未提及的問題,請在 GitHub 上開啟問題通知我們。