預先快取

服務工作者的其中一個功能,是在服務工作者安裝時,將一組檔案儲存至快取。這通常稱為「預先快取」,因為您是在使用 Service Worker 之前快取內容。

這樣做的主要原因是讓開發人員可以控管快取,也就是說,他們可以決定檔案快取的時間和時間長度,並且在不連上網路的情況下,將檔案提供給瀏覽器,也就是說,他們可以用來建立可離線運作的網頁應用程式。

Workbox 會簡化 API 並確保資產能有效下載,因此可代您處理預先快取的繁重工作。

workbox-precaching 的運作方式

第一次載入網頁應用程式時,workbox-precaching 會查看您要下載的所有素材資源,移除任何重複項目,並連結相關的服務工作者事件,以便下載及儲存素材資源。已包含版本資訊 (例如內容雜湊) 的網址可用做為快取金鑰,無須進一步修改。不含版本資訊的網址會在快取鍵中附加額外的網址查詢參數,代表 Workbox 在建構期間產生的內容雜湊。

workbox-precaching 會在服務工作者的 install 事件期間執行所有這些操作。

當使用者日後再次造訪您的網路應用程式,且您有使用不同的預先快取素材資源的新服務工作者時,workbox-precaching 會查看新清單,並根據修訂版本判斷哪些素材資源是全新的,以及哪些現有素材資源需要更新。任何新的素材資源或更新修訂版,都會在新的服務工作者 install 事件期間加入快取。

只有在 activate 事件觸發時,這個新的服務工作者才會用來回應要求。workbox-precaching 會在 activate 事件中檢查目前網址清單中是否有不再存在的快取素材資源,並從快取中移除這些素材資源。

workbox-precaching 會在每次安裝及啟用服務工作者時執行這些步驟,確保使用者擁有最新的素材資源,並只下載已變更的檔案。

提供預先快取的回應

呼叫 precacheAndRoute()addRoute() 會建立與預先快取網址要求相符的路徑

這個路徑採用的回應策略是「先快取」:系統會使用預先快取的回應,除非該快取回應不存在 (因某些意外錯誤導致),否則會改用網路回應。

呼叫 precacheAndRoute()addRoute() 的順序十分重要。通常,您會在服務工作者檔案的早期呼叫此方法,然後再透過 registerRoute() 註冊任何其他路徑。如果您先呼叫 registerRoute(),且該路徑與傳入的請求相符,系統會使用您在該額外路徑中定義的策略回應,而非 workbox-precaching 使用的快取優先策略。

預先快取清單的說明

workbox-precaching 預期物件陣列含有 urlrevision 屬性。這個陣列有時也稱為預快取資訊清單:

import {precacheAndRoute} from 'workbox-precaching';

precacheAndRoute([
  {url: '/index.html', revision: '383676'},
  {url: '/styles/app.0c9a31.css', revision: null},
  {url: '/scripts/app.0d5770.js', revision: null},
  // ... other entries ...
]);

這個清單會參照一組網址,每個網址都有各自的「修訂」資訊。

在上述範例中的第二個和第三個物件中,revision 屬性設為 null。這是因為修訂資訊位於網址本身,這通常是靜態資產的最佳做法。

第一個物件 (/index.html) 會明確設定修訂版本屬性,這是檔案內容的自動產生雜湊。與 JavaScript 和 CSS 資源不同,HTML 檔案通常無法在網址中加入修訂資訊,否則網頁內容一有變動,網站上的這些檔案連結就會中斷。

透過將修訂版本屬性傳遞至 precacheAndRoute(),Workbox 就能得知檔案何時變更,並據此更新檔案。

Workbox 提供的工具可協助您產生這份清單:

  • workbox-build:這是可用於 gulp 工作或做為 npm 執行指令碼的節點套件。
  • workbox-webpack-plugin:webpack 使用者可以使用這個外掛程式。
  • workbox-cli:我們的 CLI 也可用來產生資產清單,並將這些資產新增至服務工作者。

預先快取檔案的傳入要求

workbox-precaching 會預設執行的其中一項操作,是操控傳入的網路要求,嘗試比對已快取的檔案。這可滿足網路上的常見做法。

舉例來說,/ 的要求通常可以由 /index.html 中的檔案滿足。

以下是 workbox-precaching 預設執行的操控項目清單,以及如何變更該行為。

忽略網址參數

您可以變更含有搜尋參數的要求,移除特定值或移除所有值。

根據預設,系統會移除以 utm_ 開頭或完全比對 fbclid 的搜尋參數,這表示系統會使用 /about.html 的快取項目來滿足對 /about.html?utm_campaign=abcd 的要求。

您可以使用 ignoreURLParametersMatching 忽略不同的搜尋參數組合:

import {precacheAndRoute} from 'workbox-precaching';

precacheAndRoute(
  [
    {url: '/index.html', revision: '383676'},
    {url: '/styles/app.0c9a31.css', revision: null},
    {url: '/scripts/app.0d5770.js', revision: null},
  ],
  {
    // Ignore all URL parameters.
    ignoreURLParametersMatching: [/.*/],
  }
);

目錄索引

結尾為 / 的要求,預設會與結尾附加 index.html 的項目進行比對。這表示 / 的傳入要求可透過預先快取的項目 /index.html 自動處理。

您可以將這項設定改為其他值,或完全停用,方法是設定 directoryIndex

import {precacheAndRoute} from 'workbox-precaching';

precacheAndRoute(
  [
    {url: '/index.html', revision: '383676'},
    {url: '/styles/app.0c9a31.css', revision: null},
    {url: '/scripts/app.0d5770.js', revision: null},
  ],
  {
    directoryIndex: null,
  }
);

簡潔網址

如果要求無法與預先快取內容相符,我們會在結尾處新增 .html,以支援「清晰」網址 (又稱為「漂亮」網址)。這表示 /about 這類要求會由 /about.html 的預快取項目處理。

您可以設定 cleanUrls 來停用此行為:

import {precacheAndRoute} from 'workbox-precaching';

precacheAndRoute([{url: '/about.html', revision: 'b79cd4'}], {
  cleanUrls: false,
});

自訂操控

如果您想定義從傳入要求到預先快取素材資源的自訂配對,可以使用 urlManipulation 選項。這應該是回呼,會傳回可能相符項目的陣列。

import {precacheAndRoute} from 'workbox-precaching';

precacheAndRoute(
  [
    {url: '/index.html', revision: '383676'},
    {url: '/styles/app.0c9a31.css', revision: null},
    {url: '/scripts/app.0d5770.js', revision: null},
  ],
  {
    urlManipulation: ({url}) => {
      // Your logic goes here...
      return [alteredUrlOption1, alteredUrlOption2];
    },
  }
);

進階用途

直接使用 PrecacheController

根據預設,workbox-precaching 會為您設定 installactivate 事件監聽器。如果您需要更多控制權,對於熟悉 Service Worker 的開發人員來說,這可能不是理想做法。

您可以直接使用 PrecacheController 來新增項目至預先快取,並決定這些資產的安裝時間和清除時間,而非使用預設匯出項目。

import {PrecacheController} from 'workbox-precaching';

const precacheController = new PrecacheController();
precacheController.addToCacheList([
  {url: '/styles/example-1.abcd.css', revision: null},
  {url: '/styles/example-2.1234.css', revision: null},
  {url: '/scripts/example-1.abcd.js', revision: null},
  {url: '/scripts/example-2.1234.js', revision: null},
]);

precacheController.addToCacheList([{
  url: '/index.html',
  revision: 'abcd',
}, {
  url: '/about.html',
  revision: '1234',
}]);

self.addEventListener('install', (event) => {
  // Passing in event is required in Workbox v6+
  event.waitUntil(precacheController.install(event));
});

self.addEventListener('activate', (event) => {
  // Passing in event is required in Workbox v6+
  event.waitUntil(precacheController.activate(event));
});

self.addEventListener('fetch', (event) => {
  const cacheKey = precacheController.getCacheKeyForURL(event.request.url);
  event.respondWith(caches.match(cacheKey).then(...));
});

直接讀取預先快取的素材資源

有時您可能需要直接讀取預先快取的素材資源,而非在 workbox-precaching 可自動執行的路徑設定之外。舉例來說,您可能會想預先快取部分 HTML 範本,然後在建構完整回應時擷取並使用這些範本。

一般來說,您可以使用 Cache Storage API 取得預先快取的 Response 物件,但有一個小問題:呼叫 cache.match() 時需要使用的網址快取鍵可能包含 workbox-precaching 自動建立及維護的版本控制參數。

如要取得正確的快取索引鍵,您可以呼叫 getCacheKeyForURL(),傳入原始網址,然後使用結果對適當的快取執行 cache.match()

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

const cache = await caches.open(cacheNames.precache);
const response = await cache.match(getCacheKeyForURL('/precached-file.html'));

或者,如果您只需要預先快取的 Response 物件,可以呼叫 matchPrecache(),系統會自動使用正確的快取索引鍵,並在正確的快取中搜尋:

import {matchPrecache} from 'workbox-precaching';

const response = await matchPrecache('/precached-file.html');

清除舊的預先快取

大多數 Workbox 版本都會維持相同的格式來儲存預快取資料,舊版 Workbox 建立的預快取資料通常可由新版版本直接使用。不過,預先快取儲存空間偶爾會發生重大變更,導致現有使用者必須重新下載所有內容,並使先前預先快取的資料失效。(Workbox v3 和 v4 版本之間發生了這種變更)。

這類過時的資料不應影響正常運作,但會影響整體儲存空間配額用量,因此建議您明確刪除這類資料,以免造成使用者困擾。方法是將 cleanupOutdatedCaches() 新增至服務工作者,或是設定 cleanupOutdatedCaches: true (如果您使用 Workbox 的建構工具產生服務工作者)。

使用子資源完整性

有些開發人員可能希望在從網路擷取先前快取的網址時,能透過子資源完整性強制執行額外保證。

您可以將名為 integrity 的額外選用屬性新增至預先快取資訊清單中的任何項目。如果提供此值,系統會在建構用於填入快取的 Request 時,將其用作 integrity。如果不一致,預先快取程序就會失敗。

決定哪些預先快取資訊清單項目應具有 integrity 屬性,以及找出要使用的適當值,都超出 Workbox 建構工具的範圍。相反地,如果開發人員想選擇採用這項功能,則應修改 Workbox 產生的預先快取資訊清單,自行加入適當的資訊。Workbox 的建構工具設定中的 manifestTransform 選項可協助您:

const ssri = require('ssri');

const integrityManifestTransform = (originalManifest, compilation) => {
  const warnings = [];
  const manifest = originalManifest.map(entry => {
    // If some criteria match:
    if (entry.url.startsWith('...')) {
      // This has to be a synchronous function call, for example:
      // compilation will be set when using workbox-webpack-plugin.
      // When using workbox-build directly, you can read the file's
      // contents from disk using, e.g., the fs module.
      const asset = compilation.getAsset(entry.url);
      entry.integrity = ssri.fromData(asset.source.source()).toString();

      // Push a message to warnings if needed.
    }
    return entry;
  });

  return {warnings, manifest};
};

// Then add manifestTransform: [integrityManifestTransform]
// to your Workbox build configuration.

類型

CleanupResult

屬性

  • deletedCacheRequests

    string[]

InstallResult

屬性

  • notUpdatedURLs

    string[]

  • updatedURLs

    string[]

PrecacheController

有效率地預先快取素材資源。

屬性

  • 建構函式

    void

    建立新的 PrecacheController。

    constructor 函式如下所示:

    (options?: PrecacheControllerOptions) => {...}

    • 選項

      PrecacheControllerOptions 選用

  • 策略

    策略

  • 啟用

    void

    刪除目前預先快取資訊清單中不再存在的素材資源。在服務工作者啟用事件中呼叫此方法。

    注意:這個方法會為您呼叫 event.waitUntil(),因此您不需要在事件處理常式中自行呼叫。

    activate 函式如下所示:

    (event: ExtendableEvent) => {...}

    • 活動

      ExtendableEvent

  • addToCacheList

    void

    這個方法會將項目新增至預先快取清單,移除重複項目,並確保資訊有效。

    addToCacheList 函式如下所示:

    (entries: (string | PrecacheEntry)[]) => {...}

    • 項目

      (string | PrecacheEntry)[]

      要預先快取的項目陣列。

  • createHandlerBoundToURL

    void

    傳回函式,該函式會在預先快取中查詢 url (考量帳戶修訂資訊),並傳回對應的 Response

    createHandlerBoundToURL 函式如下所示:

    (url: string) => {...}

    • 網址

      字串

      預先快取的網址,用於查詢 Response

  • getCacheKeyForURL

    void

    傳回用於儲存特定網址的快取鍵。如果該網址未經過版本化,例如 `/index.html',則快取金鑰會是原始網址,並附加搜尋參數。

    getCacheKeyForURL 函式如下所示:

    (url: string) => {...}

    • 網址

      字串

      您要查詢快取索引鍵的網址。

    • returns

      字串

      與原始網址的快取索引鍵相對應的版本網址,如果該網址未預先快取,則為未定義。

  • getCachedURLs

    void

    傳回目前服務工作者已預先快取的所有網址清單。

    getCachedURLs 函式如下所示:

    () => {...}

    • returns

      string[]

      預先快取的網址。

  • getIntegrityForCacheKey

    void

    getIntegrityForCacheKey 函式如下所示:

    (cacheKey: string) => {...}

    • cacheKey

      字串

    • returns

      字串

      與快取鍵相關聯的子資源完整性,如果未設定,則為 undefined。

  • getURLsToCacheKeys

    void

    傳回已快取網址與對應快取索引的對應項目,並考量網址的修訂資訊。

    getURLsToCacheKeys 函式如下所示:

    () => {...}

    • returns

      Map<stringstring>

      快取金鑰對應的網址。

  • 安裝

    void

    預先快取新的素材資源和更新的素材資源。請從服務工作者安裝事件呼叫這個方法。

    注意:這個方法會為您呼叫 event.waitUntil(),因此您不需要在事件處理常式中自行呼叫。

    install 函式如下所示:

    (event: ExtendableEvent) => {...}

    • 活動

      ExtendableEvent

  • matchPrecache

    void

    這個函式可用來取代 cache.match(),但有以下差異:

    • 它知道預先快取的名稱,並只檢查該快取。
    • 您可以傳入「原始」網址,而無需提供版本化參數,系統會自動查詢該網址目前有效修訂版本的正確快取鍵。

    例如:matchPrecache('index.html') 會為目前有效的服務工作者找到正確的預先快取回應,即使實際快取鍵為 '/index.html?__WB_REVISION__=1234abcd' 也一樣。

    matchPrecache 函式如下所示:

    (request: string | Request) => {...}

    • 申請。

      字串 | 要求

      在預先快取中查詢的鍵 (不含修訂參數)。

    • returns

      Promise<Response>

  • precache

    void

    在服務 worker 安裝時,將項目新增至預先快取清單、移除任何重複項目,並將檔案儲存在快取中。

    這個方法可以多次呼叫。

    precache 函式如下所示:

    (entries: (string | PrecacheEntry)[]) => {...}

PrecacheEntry

屬性

  • 完整性

    string 選填

  • 修訂

    string 選填

  • 網址

    字串

PrecacheFallbackPlugin

PrecacheFallbackPlugin 可讓您在特定策略無法產生回應時,指定要使用的「離線備用」回應。

這項作業會攔截 handlerDidError 外掛程式回呼,並傳回已快取的回應,自動考量預期的修訂參數。

除非您明確將 PrecacheController 例項傳入建構函式,否則系統會使用預設例項。一般來說,大多數開發人員都會使用預設值。

屬性

  • 建構函式

    void

    使用相關聯的 fallbackURL 建構新的 PrecacheFallbackPlugin。

    constructor 函式如下所示:

    (config: object) => {...}

    • config

      物件

      • fallbackURL

        字串

        如果相關策略無法產生回應,則會使用預先快取的網址做為備用網址。

      • precacheController

PrecacheRoute

workbox-routing.Route 的子類別,會取得 workbox-precaching.PrecacheController 例項,並使用該例項比對傳入的要求,以及處理從預先快取擷取的回應。

屬性

PrecacheRouteOptions

屬性

  • cleanURLs

    boolean 選填

  • directoryIndex

    string 選填

  • ignoreURLParametersMatching

    RegExp[] 選填

  • urlManipulation

PrecacheStrategy

workbox-strategies.Strategy 實作項目,專門用於搭配 workbox-precaching.PrecacheController 使用,同時快取及擷取預先快取的素材資源。

注意:建立 PrecacheController 時,系統會自動建立此類別的例項;您通常不需要自行建立。

屬性

  • 建構函式

    void

    constructor 函式如下所示:

    (options?: PrecacheStrategyOptions) => {...}

    • 選項

      PrecacheStrategyOptions 選用

  • cacheName

    字串

  • fetchOptions

    RequestInit 選填

  • matchOptions

    CacheQueryOptions 選填

  • 外掛程式
  • copyRedirectedCacheableResponsesPlugin
  • defaultPrecacheCacheabilityPlugin
  • _awaitComplete

    void

    _awaitComplete 函式如下所示:

    (responseDone: Promise<Response>, handler: StrategyHandler, request: Request, event: ExtendableEvent) => {...}

    • responseDone

      Promise<Response>

    • handler
    • 申請。

      要求

    • 活動

      ExtendableEvent

    • returns

      Promise<void>

  • _getResponse

    void

    _getResponse 函式如下所示:

    (handler: StrategyHandler, request: Request, event: ExtendableEvent) => {...}

    • returns

      Promise<Response>

  • _handleFetch

    void

    _handleFetch 函式如下所示:

    (request: Request, handler: StrategyHandler) => {...}

    • returns

      Promise<Response>

  • _handleInstall

    void

    _handleInstall 函式如下所示:

    (request: Request, handler: StrategyHandler) => {...}

    • returns

      Promise<Response>

  • 帳號

    void

    執行要求策略,並傳回 Promise,該 Promise 會與 Response 解析,並叫用所有相關外掛程式回呼。

    當策略例項與 Workbox workbox-routing.Route 註冊時,系統會在路徑相符時自動呼叫這個方法。

    或者,您也可以將這個方法傳遞至 event.respondWith(),以便在獨立的 FetchEvent 事件監聽器中使用。

    handle 函式如下所示:

    (options: FetchEvent | HandlerCallbackOptions) => {...}

    • returns

      Promise<Response>

  • handleAll

    void

    workbox-strategies.Strategy~handle 類似,但它不會傳回解析為 ResponsePromise,而是會傳回 [response, done] 承諾的元組,其中前者 (response) 等同於 handle() 傳回的內容,後者則是承諾,一旦執行策略時新增至 event.waitUntil() 的任何承諾完成,就會解析。

    您可以等待 done 應許,確保策略執行的任何額外工作 (通常是快取回應) 都能順利完成。

    handleAll 函式如下所示:

    (options: FetchEvent | HandlerCallbackOptions) => {...}

    • returns

      [Promise<Response>, Promise<void>]

      由 [response, done] 承諾組成的元組,可用於判斷回應何時解析,以及處理程序何時完成所有工作。

urlManipulation()

workbox-precaching.urlManipulation(
  {
url }: object,
)

類型

函式

參數

  • { url }

    物件

    • 網址

      網址

傳回

  • URL[]

方法

addPlugins()

workbox-precaching.addPlugins(
  plugins: WorkboxPlugin[],
)

將外掛程式新增至預先快取策略。

參數

addRoute()

workbox-precaching.addRoute(
  options?: PrecacheRouteOptions,
)

fetch 事件監聽器新增至服務工作者,以便使用預先快取的素材資源回應 [網路要求]https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers#Custom_responses_to_requests

針對未預先快取的資產提出要求時,系統不會回應 FetchEvent,讓事件可傳送至其他 fetch 事件事件監聽器。

參數

cleanupOutdatedCaches()

workbox-precaching.cleanupOutdatedCaches()

新增 activate 事件監聽器,這會清理舊版 Workbox 建立的不相容預先快取內容。

createHandlerBoundToURL()

workbox-precaching.createHandlerBoundToURL(
  url: string,
)

輔助函式,可在預設 PrecacheController 例項上呼叫 PrecacheController#createHandlerBoundToURL

如果您要建立自己的 PrecacheController,請在該例項上呼叫 PrecacheController#createHandlerBoundToURL,而不要使用這個函式。

參數

  • 網址

    字串

    預先快取的網址,用於查詢 Response

getCacheKeyForURL()

workbox-precaching.getCacheKeyForURL(
  url: string,
)

接收網址,並傳回可用於在預先快取中查詢項目的對應網址。

如果提供相對網址,系統會使用服務工作者檔案的位置做為基礎。

如果快取的項目沒有修訂版本資訊,快取鍵就會與原始網址相同。

如果快取的項目含有修訂版本資訊,快取鍵將會是原始網址,並加上用於追蹤修訂版本資訊的查詢參數。

參數

  • 網址

    字串

    要查詢快取鍵的網址。

傳回

  • 字串 | 未定義

    對應該網址的快取索引鍵。

matchPrecache()

workbox-precaching.matchPrecache(
  request: string | Request,
)

輔助函式,可在預設 PrecacheController 例項上呼叫 PrecacheController#matchPrecache

如果您要建立自己的 PrecacheController,請在該例項上呼叫 PrecacheController#matchPrecache,而不要使用這個函式。

參數

  • 申請。

    字串 | 要求

    在預先快取中查詢的鍵 (不含修訂參數)。

傳回

  • Promise<Response | undefined>

precache()

workbox-precaching.precache(
  entries: (string | PrecacheEntry)[],
)

在服務 worker 安裝時,將項目新增至預先快取清單、移除任何重複項目,並將檔案儲存在快取中。

這個方法可以多次呼叫。

請注意:這個方法不會為您提供任何快取檔案。只會預先快取檔案。如要回應網路要求,請呼叫 workbox-precaching.addRoute

如果您有要預先快取的單一檔案陣列,只需呼叫 workbox-precaching.precacheAndRoute 即可。

參數

precacheAndRoute()

workbox-precaching.precacheAndRoute(
  entries: (string | PrecacheEntry)[],
  options?: PrecacheRouteOptions,
)

這個方法會將項目新增至預先快取清單,並新增回應擷取事件的路徑。

這是方便方法,可在單一呼叫中呼叫 workbox-precaching.precacheworkbox-precaching.addRoute

參數