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
需要具備 url
和 revision
屬性的物件陣列。這個陣列有時也稱為預載資訊清單:
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
會為您設定 install
和 activate
事件監聽器。對於熟悉 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 選用
-
returns
-
-
策略
策略
-
啟用
void
刪除已不在目前預先快取資訊清單中的資產。 從 Service Worker 啟用事件呼叫此方法。
注意:這個方法會為您呼叫
event.waitUntil()
,因此您不必在事件處理常式中自行呼叫。activate
函式如下所示:(event: ExtendableEvent) => {...}
-
event
ExtendableEvent
-
returns
Promise<CleanupResult>
-
-
addToCacheList
void
這個方法會將項目新增至友善快取清單、移除重複內容,並確保資訊有效。
addToCacheList
函式如下所示:(entries: (string | PrecacheEntry)[]) => {...}
-
entries
(字串 | PrecacheEntry)[]
要友善載入的項目陣列。
-
-
createHandlerBoundToURL
void
傳回在預快取中查詢
url
的函式 (擷取帳戶修訂版本資訊),並傳回對應的Response
。createHandlerBoundToURL
函式如下所示:(url: string) => {...}
-
網址
字串
用於查詢
Response
的預先快取網址。
-
returns
-
-
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
-
returns
Promise<InstallResult>
-
-
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)[]) => {...}
-
entries
(字串 | PrecacheEntry)[]
-
PrecacheEntry
屬性
-
完整性
字串 選用
-
修訂版本
字串 選用
-
網址
字串
PrecacheFallbackPlugin
PrecacheFallbackPlugin
可讓您指定「離線備用」回應,供特定策略無法產生回應時使用。
為此,這項功能會攔截 handlerDidError
外掛程式回呼並傳回預先快取回應,自動將預期的修訂版本參數納入考量。
除非您將 PrecacheController
例項明確傳入建構函式,否則系統會使用預設執行個體。一般而言,大部分的開發人員最終都會採用預設值。
屬性
-
建構函式
void
使用相關聯的 backupURL 建構新的 PrecacheFallbackPlugin。
constructor
函式如下所示:(config: object) => {...}
-
config
物件
-
fallbackURL
字串
在相關策略無法產生回應時,用來當做備用方案的預先快取網址。
-
precacheController
-
-
returns
-
PrecacheRoute
workbox-routing.Route
的子類別,使用 workbox-precaching.PrecacheController
執行個體,並用於比對傳入要求並處理從預快取中擷取回應。
屬性
-
建構函式
void
constructor
函式如下所示:(precacheController: PrecacheController, options?: PrecacheRouteOptions) => {...}
-
precacheController
用於比對要求及回應擷取事件的
PrecacheController
執行個體。 -
選項
-
returns
-
-
catchHandler
-
handler
-
相符項目
-
method
HTTPMethod
-
setCatchHandler
void
setCatchHandler
函式如下所示:(handler: RouteHandler) => {...}
-
handler
回呼函式可傳回 Promise 解析給回應
-
PrecacheRouteOptions
屬性
-
cleanURLs
布林值 (選用)
-
directoryIndex
字串 選用
-
ignoreURLParametersMatching
RegExp[] 選填
-
urlManipulation
urlManipulation (選用)
PrecacheStrategy
專為與 workbox-precaching.PrecacheController
搭配使用的 workbox-strategies.Strategy
實作,可快取及擷取預先快取資產。
注意:建立 PrecacheController
時,系統會自動建立此類別的例項;您通常不需要自行建立這個類別。
屬性
-
建構函式
void
constructor
函式如下所示:(options?: PrecacheStrategyOptions) => {...}
-
選項
PrecacheStrategyOptions 選用
-
returns
-
-
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) => {...}
-
handler
-
申請。
要求
-
event
ExtendableEvent
-
returns
Promise<Response>
-
-
_帳號代碼
void
_handleFetch
函式如下所示:(request: Request, handler: StrategyHandler) => {...}
-
申請。
要求
-
handler
-
returns
Promise<Response>
-
-
_handle 安裝
void
_handleInstall
函式如下所示:(request: Request, handler: StrategyHandler) => {...}
-
申請。
要求
-
handler
-
returns
Promise<Response>
-
-
帳號
void
執行要求策略並傳回會使用
Response
解析的Promise
,並叫用所有相關外掛程式回呼。透過 Workbox
workbox-routing.Route
註冊策略執行個體時,系統會在路徑比對相符時自動呼叫這個方法。或者,您也可以將此方法傳遞至
event.respondWith()
,以在獨立的FetchEvent
事件監聽器中使用。handle
函式如下所示:(options: FetchEvent | HandlerCallbackOptions) => {...}
-
選項
FetchEvent | HandlerCallbackOptions
FetchEvent
或具有下列屬性的物件。
-
returns
Promise<Response>
-
-
handleAll
void
與
workbox-strategies.Strategy~handle
類似,但前者不會傳回解析為Response
的Promise
,而是會傳回[response, done]
承諾組合,其中前者 (response
) 等同於handle()
傳回的內容,後者則是在執行策略的過程中,新增至event.waitUntil()
的任何承諾,皆可解決問題。您可以等待
done
承諾,確保策略執行的所有額外工作 (通常是快取回應) 都能順利完成。handleAll
函式如下所示:(options: FetchEvent | HandlerCallbackOptions) => {...}
-
選項
FetchEvent | HandlerCallbackOptions
FetchEvent
或具有下列屬性的物件。
-
returns
[Promise<Response>, Promise<void>]
[response, finished] 的組合,可用於判斷回應解析的時間,以及處理常式完成所有作業的時間。
-
urlManipulation()
workbox-precaching.urlManipulation(
{ url }: object,
)
類型
功能
參數
-
{ 網址 }
物件
-
網址
網址
-
傳回
-
網址 []
方法
參數
-
外掛程式
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
即可。
參數
-
entries
(字串 | PrecacheEntry)[]
precacheAndRoute()
workbox-precaching.precacheAndRoute(
entries: (string | PrecacheEntry)[],
options?: PrecacheRouteOptions,
)
這個方法會將項目新增至友善快取清單,並新增路徑回應擷取事件。
這是一種便利的方法,可以在單一呼叫中呼叫 workbox-precaching.precache
和 workbox-precaching.addRoute
。
參數
-
entries
(字串 | PrecacheEntry)[]
要友善載入的項目陣列。
-
選項