workbox-window
套件是一組模組,用來在
window
項背景資訊,也就是
你的實際內容因為前者是其他工作箱的不足之處
在 Service Worker 中執行的套件。
workbox-window
的主要特色/目標為:
- 如要簡化服務工作處理程序的註冊和更新流程, 開發人員找出 Service Worker 生命週期中最重要的時刻,並簡化相關程序 回應這些時刻
- 防止開發人員做出最常見的錯誤。
- 實現更簡便的溝通 在 Service Worker 中執行的程式碼與視窗中執行的程式碼之間。
匯入及使用 Workbox 視窗
workbox-window
套件的主要進入點為 Workbox
類別,而
您可以從我們的 CDN 或
JavaScript 統合工具
使用我們的 CDN
要從我們的 CDN 匯入網站的 Workbox
類別,最簡單的方法就是:
<script type="module">
import {Workbox} from 'https://storage.googleapis.com/workbox-cdn/releases/6.4.1/workbox-window.prod.mjs';
if ('serviceWorker' in navigator) {
const wb = new Workbox('/sw.js');
wb.register();
}
</script>
請注意,本範例使用 <script type="module">
和 import
陳述式:
載入 Workbox
類別。雖然您可能會覺得
您必須把這個
程式碼,以便在舊版瀏覽器中正常運作,但其實並非必要。
所有支援 Service 工作站的主要瀏覽器也會支援原生 JavaScript 模組,因此完全 可以將這個程式碼提供給任何瀏覽器 (舊版瀏覽器只會忽略這段程式碼)。
使用 JavaScript 軟體包載入 Workbox
雖然 workbox-window
絕對不需要工具,但如果您的
開發基礎架構已包括許多整合工具
可使用的 webpack 或 Rollup
與 npm 依附元件搭配使用,即可將其用於
載入 workbox-window
。
首先
安裝
workbox-window
做為應用程式的依附元件:
npm install workbox-window
接著,在應用程式的其中一個 JavaScript 檔案中,import
工作箱是由
參照 workbox-window
套件名稱:
import {Workbox} from 'workbox-window';
if ('serviceWorker' in navigator) {
const wb = new Workbox('/sw.js');
wb.register();
}
如果您的 Bundler 支援透過動態匯入陳述式分割程式碼,
您也可以有條件地載入 workbox-window
,這應該有助於減少
網頁主要素材資源組合的大小
雖然 workbox-window
很小,但其實並不合理
需要與網站的核心應用程式邏輯 (即服務工作處理程序) 載入
從大自然角度來看,都是進步的一大進步
if ('serviceWorker' in navigator) {
const {Workbox} = await import('workbox-window');
const wb = new Workbox('/sw.js');
wb.register();
}
進階郵件分類概念
與在 Service Worker 中執行的 Workbox 套件不同,建構檔案
由 workbox-window
的
main
和
module
欄位位於
package.json
已轉成 ES5。因此與當今的
以及建立工具,其中有些不允許開發人員傳輸
其 node_module
依附元件。
如果您的建構系統「確實」允許您轉譯依附元件 (或 您不必轉譯任何程式碼) 而非套件本身。
以下列出匯入 Workbox
的各種方法,以及
分別傳回的結果:
// Imports a UMD version with ES5 syntax
// (pkg.main: "build/workbox-window.prod.umd.js")
const {Workbox} = require('workbox-window');
// Imports the module version with ES5 syntax
// (pkg.module: "build/workbox-window.prod.es5.mjs")
import {Workbox} from 'workbox-window';
// Imports the module source file with ES2015+ syntax
import {Workbox} from 'workbox-window/Workbox.mjs';
範例
匯入 Workbox
類別後,即可使用該類別註冊
必須與 Service Worker 互動,以下列舉幾個可能的應用方式
應用程式中的 Workbox
:
註冊 Service Worker,並在首次啟用 Service Worker 時通知使用者
許多網頁應用程式的使用者 Service Worker 都能預先快取資產,讓應用程式正常運作 離線載入檔案在某些情況下 使用者將應用程式恢復為可離線使用。
const wb = new Workbox('/sw.js');
wb.addEventListener('activated', event => {
// `event.isUpdate` will be true if another version of the service
// worker was controlling the page when this version was registered.
if (!event.isUpdate) {
console.log('Service worker activated for the first time!');
// If your service worker is configured to precache assets, those
// assets should all be available now.
}
});
// Register the service worker after event listeners have been added.
wb.register();
如果 Service Worker 已安裝,但仍無法順利啟用,請通知使用者
當現有 Service Worker 控制的網頁註冊新的服務時 根據預設,Service Worker 要等到所有用戶端,才會啟動 由初始 Service Worker 控制的所有元件已完全卸載。
這是開發人員常會感到困惑,尤其是在 重新載入目前網頁不會導致新的 Service Worker 啟用。
為了盡量減少混淆
並清楚掌握狀況
Workbox
類別提供 waiting
事件,您可以監聽:
const wb = new Workbox('/sw.js');
wb.addEventListener('waiting', event => {
console.log(
`A new service worker has installed, but it can't activate` +
`until all tabs running the current version have fully unloaded.`
);
});
// Register the service worker after event listeners have been added.
wb.register();
通知使用者 workbox-broadcast-update
套件的快取更新
workbox-broadcast-update
套件可讓您從快取提供內容 (以便快速傳遞),同時
能夠通知使用者更新內容 (使用
「過時」重新驗證策略)。
如要從視窗接收這些更新,您可以監聽message
事件的
類型 CACHE_UPDATED
:
const wb = new Workbox('/sw.js');
wb.addEventListener('message', event => {
if (event.data.type === 'CACHE_UPDATED') {
const {updatedURL} = event.data.payload;
console.log(`A newer version of ${updatedURL} is available!`);
}
});
// Register the service worker after event listeners have been added.
wb.register();
將要快取的網址清單傳送給 Service Worker
在某些應用程式中,系統可能會 但在建構階段預先快取,但有些應用程式提供完全不同的頁面, 以使用者首先到達的網址為依據
如果應用程式屬於後者,只快取資產就適合
也就是使用者造訪特定網頁所需的時間。使用
workbox-routing
套件,您可以
將網址清單傳送給路由器進行快取,系統便會根據
例如路由器本身所定義的規則
此範例會將網頁載入的網址清單傳送至路由器 會啟動新的 Service Worker。請注意,您可以傳送「所有」網址,因為 系統會快取符合 Service Worker 中已定義路徑的網址。
const wb = new Workbox('/sw.js');
wb.addEventListener('activated', event => {
// Get the current page URL + all resources the page loaded.
const urlsToCache = [
location.href,
...performance.getEntriesByType('resource').map(r => r.name),
];
// Send that list of URLs to your router in the service worker.
wb.messageSW({
type: 'CACHE_URLS',
payload: {urlsToCache},
});
});
// Register the service worker after event listeners have been added.
wb.register();
重要的 Service Worker 生命週期時刻
服務工作站生命週期 對我們來說,是相當複雜的挑戰,可能並不容易理解。部分原因在於 而是必須處理所有可能使用的極端情況 Service Worker (例如註冊多個 Service Worker、註冊 Service Worker 會註冊服務工作處理程序 不同的名稱等等)。
不過,大多數實作 Service Worker 的開發人員都不需要擔心 這些極端情況,因為其使用很簡單。多數開發人員 每次載入網頁時,系統只會註冊一個 Service Worker,而且不會變更 Service Worker 的名稱 部署到伺服器中
Workbox
類別採用這個較簡單的 Service Worker 生命週期檢視畫面
將所有 Service Worker 註冊分為兩個類別:執行個體的
已註冊的 Service Worker 和外部 Service Worker:
- 已註冊的 Service Worker:開始安裝為
Workbox
例項呼叫register()
或已經啟用的項目 Service Worker 表示呼叫register()
時,不會在登錄時觸發updatefound
事件。 - External Service Worker:開始安裝的 Service Worker
單獨呼叫
register()
的Workbox
例項。這通常 當使用者在其他分頁中開啟您的網站時,就會發生這個事件。如果 事件源自外部 Service Worker,事件的isExternal
屬性會設為true
。
以下說明這兩種 Service Worker 的特性。 重要服務工作處理程序生命週期時刻,以及開發人員建議 處理方式:
第一次安裝 Service Worker 時
建議您在首次安裝 Service Worker 時進行安裝 與您處理日後所有更新的方式不同
在 workbox-window
中,您可以先區分版本
安裝及後續更新程式,方法是檢查 isUpdate
後續事件。如果是第一次安裝,isUpdate
會
false
。
const wb = new Workbox('/sw.js');
wb.addEventListener('installed', event => {
if (!event.isUpdate) {
// First-installed code goes here...
}
});
wb.register();
找到 Service Worker 的更新版本時
新的 Service Worker 開始安裝,但目前已有版本
控制網頁時,下列所有事件的 isUpdate
屬性將會
應為 true
。
在這情況下的回應方式通常與第 種情況不同 安裝,藉此控管使用者接收更新的時間和方式。
發現 Service Worker 未預期的版本時
有時使用者會讓網站在背景分頁中長時間開啟一段時間 讓應用程式從可以最快做出回應的位置 回應使用者要求訪客甚至可能在未察覺的情況下,開啟新分頁並前往您的網站 他們在背景分頁中開啟網站在這些情況下 您的網站同時執行了兩個版本 可以為您呈現一些有趣的問題
舉例來說,假設您的網站 A 和分頁 B 分別執行 v1 執行 v2載入分頁 B 後,該分頁將由服務版本控管 傳送 v1 版本的工作站,但伺服器傳回網頁 (如果使用 網路優先的快取策略 ) 會包含所有 v2 資產。
不過,這通常不是分頁 B 的問題,因為當您編寫 v2 時 您知道第 1 版程式碼的運作方式了,不過, ,因為第 1 版程式碼無法預測 可能會有什麼影響
為協助處理這類情況,workbox-window
也會調度生命週期
偵測到「外部」的更新時觸發的事件Service Worker 中
「外部」意指任何非現行 Workbox
版本的版本
執行個體已註冊。
從 Workbox v6 以上版本,這些事件等同於
上述,而且在每個事件中加入 isExternal: true
屬性後,
物件。如果網頁應用程式需要實作特定邏輯來處理
「外部」服務工作處理程序,您可以在事件處理常式中查看該屬性。
避免常見錯誤
Workbox 提供開發人員記錄功能,是 Workbox 最實用的功能之一。且
對 workbox-window
而言更是如此。
我們瞭解,透過 Service Worker 進行開發經常令人困惑,而且在過程中 結果會與您的預期有所落差 可能很難察覺
舉例來說,當您變更 Service Worker 並重新載入頁面時, 您的瀏覽器可能不會有這項變更。最有可能的原因是 您的服務工作處理程序還在等候啟用。
但透過 Workbox
類別註冊 Service Worker 時,您將
開發人員主控台中所有生命週期狀態的異動通知
協助偵錯,找出哪些地方不如預期。
此外,開發人員初次使用 Service Worker 時常犯的錯誤為 註冊 Service Worker 範圍錯誤。
為避免這種情況發生,Workbox
類別會在出現以下情況時發出警告:
註冊 Service Worker 的網頁不在該 Service Worker 範圍內。是
如果 Service Worker 已啟用但尚未運作,系統也會發出警告
控制網頁:
服務工作處理程序的通訊視窗
大多數進階 Service Worker 需要在
Service Worker 和視窗。Workbox
類別也有助於解決這個問題
提供 messageSW()
方法,該方法會postMessage()
執行個體的
並等候回應。
儘管您可以傳送任何格式的資料給 Service Worker,但共用的格式 所有 Workbox 套件都屬於一個物件 (包含三個屬性 選用):
透過 messageSW()
方法傳送的訊息會使用 MessageChannel
,以便接收端
回應使用者如要回覆訊息,你可以撥打電話
event.ports[0].postMessage(response)
。
messageSW()
方法傳回的承諾會解析為任何 response
您進行回覆時
以下範例說明如何從視窗將訊息傳送至 Service Worker,並
取得回覆第一個程式碼區塊是
而第二個區塊則使用 Workbox
類別將
然後等候回覆:
sw.js 中的程式碼:
const SW_VERSION = '1.0.0';
addEventListener('message', event => {
if (event.data.type === 'GET_VERSION') {
event.ports[0].postMessage(SW_VERSION);
}
});
在 main.js 中的程式碼 (在視窗中執行):
const wb = new Workbox('/sw.js');
wb.register();
const swVersion = await wb.messageSW({type: 'GET_VERSION'});
console.log('Service Worker version:', swVersion);
管理版本不相容的問題
以上範例說明如何檢查 Service Worker 的實作方式 從視窗下載版本這個範例之所以使用,是因為 因此,關鍵在於 請注意,您的 Service Worker 可能執行的版本不同 網頁程式碼運作期間,要處理此問題 問題取決於是否優先放送網頁 也就是快取優先
網路優先
優先提供網頁聯播網時,您的使用者始終可以 下載最新版本的 HTML。但是使用者初次造訪 Gmail 時 使用者重新造訪您的網站 (部署更新後) 將會取得的 HTML 程式碼 但在瀏覽器中運作的 Service Worker 先前安裝的版本 (可能有許多舊版本)。
請務必瞭解這種可能性,因為 JavaScript 是否已載入 您目前的網頁版本會將訊息傳送到 因此該版本可能不知道該如何回應 ( 使用不相容的格式)。
因此,建議您一律啟用 Service Worker 的版本,並檢查 ,再執行任何重要工作。
舉例來說,在上述程式碼中,如果指定的 Service Worker 版本
messageSW()
呼叫比預期版本舊,可以直接等候
直到有更新 (呼叫 register()
時會發生這種狀況)。在
通知使用者或更新相關資訊;您也可以手動
跳過等候階段
即可立即啟用新的 Service Worker。
先快取
相對於優先提供網頁快取
首先,您會發現
頁面版本一開始會與
Service Worker (因為系統會提供內容)。因此,這個問題安全無虞
,立即使用 messageSW()
。
不過,如果找到並啟用 Service Worker 的更新版本,
當您的網頁呼叫 register()
(也就是刻意略過等待階段) 時,
已面臨危險,因此傳送訊息也會不夠安全。
管理這種可能性的方法之一,就是採用 可讓您區分破壞性更新和非破壞性更新。 若是發生破壞性更新,則可以直接告知 Service Worker。建議您警告使用者他們正在執行舊裝置 的網頁版本,並建議他們重新載入頁面以更新。
略過等待小幫手
視窗連線至 Service Worker 訊息的常見慣例是傳送
{type: 'SKIP_WAITING'}
訊息,指示已安裝至應用程式的 Service Worker
跳過等待階段
然後啟動
自 Workbox v6 起,messageSkipWaiting()
方法可用來傳送
{type: 'SKIP_WAITING'}
訊息傳送給與
目前的 Service Worker 註冊。這項功能會在排除
等待 Service Worker。
類型
Workbox
類別,協助處理 Service Worker 的註冊、更新和 Service Worker 生命週期事件的回應。
屬性
-
建構函式
void
使用指令碼網址和 Service Worker 建立新的 Workbox 執行個體 只要設定成「自動重新啟動」 和「在主機維護期間」選項即可指令碼網址和選項與 呼叫 navigator.serviceWorker.register(scriptURL, options)。
constructor
函式如下所示:(scriptURL: string | TrustedScriptURL, registerOptions?: object) => {...}
-
scriptURL
string |TrustedScriptURL
Service Worker 指令碼 與這個執行個體建立關聯使用 支援
TrustedScriptURL
。 -
registerOptions
物件 optional
-
returns
-
-
已啟用
Promise<ServiceWorker>
-
控制
Promise<ServiceWorker>
-
getSW
void
使用符合指令碼網址的 Service Worker 參照進行解析 並在執行個體可用後立即執行
如果註冊時已有啟用中的或等待服務 具有相符指令碼網址的 worker 便會使用 (等待 Service Worker 會優先於使用中的 Service Worker,如果兩者 比對內容。因為等待服務工作處理程序可能登錄更多 )。 如果註冊時沒有相符的有效或等待服務工作人員 但直到找到更新並開始之後,承諾才會解決 安裝,此時會使用安裝服務工作站。
getSW
函式如下所示:() => {...}
-
returns
Promise<ServiceWorker>
-
-
messageSW
void
將傳遞的資料物件傳送至由此類別註冊的 Service Worker 執行個體 (透過
workbox-window.Workbox#getSW
) 並解析 回應 (如有)。回應可在 Service Worker 的訊息處理常式中設定 呼叫
event.ports[0].postMessage(...)
,即可解決 由messageSW()
傳回。如未設定回應,承諾就永遠不會 解析。messageSW
函式如下所示:(data: object) => {...}
-
資料
物件
要傳送至 Service Worker 的物件
-
returns
承諾<任何>
-
-
messageSkipWaiting
void
傳送
{type: 'SKIP_WAITING'}
訊息給 目前處於與目前的註冊相關聯的waiting
狀態。如果目前沒有註冊,或沒有 Service Worker 為
waiting
, 呼叫此方法不會有任何效果。messageSkipWaiting
函式如下所示:() => {...}
-
register
void
為這個執行個體指令碼網址和服務註冊 Service Worker 工作站選項。這個方法預設會將註冊延遲至下列日期之後: 視窗已經載入。
register
函式如下所示:(options?: object) => {...}
-
選項
物件 optional
-
立即
布林值 選填
-
-
returns
Promise<ServiceWorkerRegistration>
-
-
update
void
檢查已註冊的 Service Worker 的更新。
update
函式如下所示:() => {...}
-
returns
承諾<void>
-
WorkboxEventMap
屬性
WorkboxLifecycleEvent
屬性
-
isExternal
布林值 選填
-
isUpdate
布林值 選填
-
originalEvent
事件 (選填)
-
sw
ServiceWorker 選用
-
目標
WorkboxEventTarget (選用)
-
類型
typeOperator
WorkboxLifecycleEventMap
屬性
WorkboxLifecycleWaitingEvent
屬性
-
isExternal
布林值 選填
-
isUpdate
布林值 選填
-
originalEvent
事件 (選填)
-
sw
ServiceWorker 選用
-
目標
WorkboxEventTarget (選用)
-
類型
typeOperator
-
wasWaitingBeforeRegister
布林值 選填
WorkboxMessageEvent
屬性
-
資料
不限
-
isExternal
布林值 選填
-
originalEvent
活動
-
ports
typeOperator
-
sw
ServiceWorker 選用
-
目標
WorkboxEventTarget (選用)
-
類型
"訊息"
方法
messageSW()
workbox-window.messageSW(
sw: ServiceWorker,
data: object,
)
這個外掛程式會透過 postMessage
將資料物件傳送至 Service Worker,並解析
回應 (如有)。
回應可在 Service Worker 的訊息處理常式中設定
呼叫 event.ports[0].postMessage(...)
,即可解決
由 messageSW()
傳回。如未設定回應,承諾就不會
解析。
參數
-
sw
ServiceWorker
要接收訊息的 Service Worker。
-
資料
物件
要傳送至 Service Worker 的物件。
傳回
-
承諾<任何>