預先快取

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

這麼做的主要原因是,開發人員可以控制快取,亦即他們能判斷快取檔案的時間和時間長度,以及在不前往網路的情況下,將檔案提供給瀏覽器,意即可用來建立可離線運作的網頁應用程式。

Workbox 能夠簡化 API 並確保資產的下載效率,大幅減輕預先快取作業的繁瑣工作。

工作盒預先快取的運作方式

首次載入網頁應用程式時,workbox-precaching 會查看您要下載的所有資產、移除所有重複內容,並連結相關的 Service Worker 事件,以下載和儲存資產。已包含版本資訊 (例如內容雜湊) 的網址會用作快取金鑰,無需進一步修改。不包含版本管理資訊的網址會在快取金鑰後方附加一個網址查詢參數,代表 Workbox 在建構時產生的內容雜湊。

workbox-precaching 會在 Service Worker 的 install 事件執行這些工作。

當有使用者之後重新造訪網頁應用程式,且您有一個具有不同預先快取資產的新 Service Worker 時,workbox-precaching 將查看新的清單,並根據其修訂版本,判斷哪些是全新資產,以及哪些現有資產需要更新。所有新資產或更新修訂版本都會在新 Service Worker 的 install 事件中新增至快取。

在觸發其 activate 事件之前,不會使用這個新的 Service Worker 來回應要求。在 activate 事件中,workbox-precaching 會檢查目前網址清單中不再顯示的任何快取資產,並將這些資產從快取中移除。

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

提供預先快取回應

呼叫 precacheAndRoute()addRoute() 會建立與友善快取網址要求的路徑

此路徑使用的回應策略為快取優先:除非該快取回應不存在 (因為發生一些非預期的錯誤),否則系統會改用網路回應。

呼叫 precacheAndRoute()addRoute() 的順序相當重要。您通常會需要先在 Service Worker 檔案中呼叫此方法,然後再使用 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?utm_campaign=abcd 的要求將為 /about.html 的預載項目執行。

您可以使用 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.html 的預先快取項目將處理類似 /about 的要求。

如要停用此行為,請設定 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 第 3 版和第 4 版之間發生這項變更)。

這類過時資料不應幹擾正常作業,但確實會計入整體儲存空間配額,並方便使用者明確刪除。如要這麼做,請將 cleanupOutdatedCaches() 新增至 Service Worker,或者使用任一 Workbox 建構工具產生 Service Worker,則可設定 cleanupOutdatedCaches: true

使用子資源完整性

部分開發人員可能想要在從網路擷取預先快取網址時,透過子資源完整性強制執行的新增保證。

您還可以將額外的選用屬性 (名為 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

    刪除已不在目前預先快取資訊清單中的資產。 從 Service Worker 啟用事件呼叫此方法。

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

    activate 函式如下所示:

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

    • event

      ExtendableEvent

  • addToCacheList

    void

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

    addToCacheList 函式如下所示:

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

    • entries

      (字串 | PrecacheEntry)[]

      要友善載入的項目陣列。

  • createHandlerBoundToURL

    void

    傳回在預快取中查詢 url 的函式 (擷取帳戶修訂版本資訊),並傳回對應的 Response

    createHandlerBoundToURL 函式如下所示:

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

    • 網址

      字串

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

  • getCacheKeyForURL

    void

    傳回用來儲存特定網址的快取金鑰。如果該網址尚未版本 (例如「/index.html」),快取金鑰就會是原始網址,並附有搜尋參數。

    getCacheKeyForURL 函式如下所示:

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

    • 網址

      字串

      您要查詢快取金鑰的網址。

    • returns

      字串

      版本化網址,與原始網址的快取金鑰相對應;如果沒有該網址的預快取,則為未定義。

  • getCachedURLs

    void

    傳回目前 Service Worker 已預先快取的所有網址清單。

    getCachedURLs 函式如下所示:

    () => {...}

    • returns

      string[]

      友善快取網址。

  • getIntegrityForCacheKey

    void

    getIntegrityForCacheKey 函式如下所示:

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

    • cacheKey

      字串

    • returns

      字串

      與快取金鑰相關聯的子資源完整性,如未設定,則為未定義。

  • getURLsToCacheKeys

    void

    傳回友善快取網址與對應快取金鑰的對應,並將網址的修訂版本資訊納入考量。

    getURLsToCacheKeys 函式如下所示:

    () => {...}

    • returns

      地圖<stringstring>

      快取按鍵對應設定的網址。

  • 安裝

    void

    預先快取新資產和更新資產。請從 Service Worker 的安裝事件呼叫此方法。

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

    install 函式如下所示:

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

    • event

      ExtendableEvent

  • matchPrecache

    void

    這可以做為 cache.match() 的直接取代,但以下差異:

    • 它知道預先快取名稱,並且只會在該快取中檢查。
    • 您可以在沒有版本管理參數的情況下,傳入「原始」網址,而且會自動查詢該網址目前使用中修訂版本的正確快取金鑰。

    例如:matchPrecache('index.html') 會尋找目前使用中 Service Worker 的正確預先快取回應,即使實際的快取金鑰是 '/index.html?__WB_REVISION__=1234abcd' 也一樣。

    matchPrecache 函式如下所示:

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

    • 申請。

      string | 要求

      用來在預先快取中查詢的金鑰 (不含修訂參數)。

    • returns

      Promise<Response>

  • 預先快取

    void

    新增項目至友善快取清單、移除所有重複項目,並在服務工作站安裝時將檔案儲存在快取中。

    這個方法可以多次呼叫。

    precache 函式如下所示:

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

PrecacheEntry

屬性

  • 完整性

    字串 選用

  • 修訂版本

    字串 選用

  • 網址

    字串

PrecacheFallbackPlugin

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

為此,這項功能會攔截 handlerDidError 外掛程式回呼並傳回預先快取回應,自動將預期的修訂版本參數納入考量。

除非您將 PrecacheController 例項明確傳入建構函式,否則系統會使用預設執行個體。一般而言,大部分的開發人員最終都會採用預設值。

屬性

  • 建構函式

    void

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

    constructor 函式如下所示:

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

    • config

      物件

      • fallbackURL

        字串

        在相關策略無法產生回應時,用來當做備用方案的預先快取網址。

      • precacheController

PrecacheRoute

workbox-routing.Route 的子類別,使用 workbox-precaching.PrecacheController 執行個體,並用於比對傳入要求並處理從預快取中擷取回應。

屬性

PrecacheRouteOptions

屬性

  • cleanURLs

    布林值 (選用)

  • directoryIndex

    字串 選用

  • ignoreURLParametersMatching

    RegExp[] 選填

  • urlManipulation

PrecacheStrategy

專為與 workbox-precaching.PrecacheController 搭配使用的 workbox-strategies.Strategy 實作,可快取及擷取預先快取資產。

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

屬性

  • 建構函式

    void

    constructor 函式如下所示:

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

    • 選項

      PrecacheStrategyOptions 選用

  • cacheName

    字串

  • fetchOptions

    RequestInit (選用)

  • matchOptions

    CacheQueryOptions 選用

  • 外掛程式
  • copyRedirectedCacheableResponsesPlugin
  • defaultPrecacheCacheabilityPlugin
  • _等待完成

    void

    _awaitComplete 函式如下所示:

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

    • responseDone

      Promise<Response>

    • handler
    • 申請。

      要求

    • event

      ExtendableEvent

    • returns

      Promise<void>

  • _取得回應

    void

    _getResponse 函式如下所示:

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

    • returns

      Promise<Response>

  • _帳號代碼

    void

    _handleFetch 函式如下所示:

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

    • returns

      Promise<Response>

  • _handle 安裝

    void

    _handleInstall 函式如下所示:

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

    • returns

      Promise<Response>

  • 帳號

    void

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

    透過 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, finished] 的組合,可用於判斷回應解析的時間,以及處理常式完成所有作業的時間。

urlManipulation()

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

類型

功能

參數

  • { 網址 }

    物件

    • 網址

      網址

傳回

  • 網址 []

方法

addPlugins()

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

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

參數

addRoute()

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

fetch 事件監聽器新增至 Service Worker,以使用預先快取資產回應 [網路要求]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,
)

擷取網址,並傳回可用於查詢友善快取項目的對應網址。

如果提供相對網址,系統會使用 Service Worker 檔案的位置做為基礎。

針對沒有修訂版本資訊的預先快取項目,快取金鑰會與原始網址相同。

針對含有修訂版本資訊的預先快取項目,快取金鑰會是原始網址,並加上用來追蹤修訂版本資訊的查詢參數。

參數

  • 網址

    字串

    要查詢其快取金鑰的網址。

傳回

  • string | 未定義

    與該網址對應的快取金鑰。

matchPrecache()

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

可在預設 PrecacheController 執行個體上呼叫 PrecacheController#matchPrecache 的輔助函式。

如果您要自行建立 PrecacheController,請在該執行個體上呼叫 PrecacheController#matchPrecache (而非使用這個函式)。

參數

  • 申請。

    string | 要求

    用來在預先快取中查詢的金鑰 (不含修訂參數)。

傳回

  • Promise<Response | undefined>

precache()

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

新增項目至友善快取清單、移除所有重複項目,並在服務工作站安裝時將檔案儲存在快取中。

這個方法可以多次呼叫。

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

如果有多個檔案陣列需要預載,直接呼叫 workbox-precaching.precacheAndRoute 即可。

參數

precacheAndRoute()

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

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

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

參數