Le package workbox-window
est un ensemble de modules destinés à s'exécuter dans le
Le contexte window
, qui
à l'intérieur de vos pages Web. Ils complètent l'autre boîte de travail
qui s'exécutent dans le service worker.
Principales fonctionnalités et objectifs de workbox-window
:
- Simplifier le processus d'enregistrement et de mise à jour des service workers en aidant à les développeurs à identifier les moments les plus critiques du cycle de vie d'un service worker, afin de faciliter le processus pour réagir à ces moments.
- Pour éviter que les développeurs commettent les erreurs les plus courantes.
- Pour faciliter la communication entre le code exécuté dans le service worker et le code exécuté dans la fenêtre.
Importation et utilisation de la fenêtre de boîte de travail
Le point d'entrée principal du package workbox-window
est la classe Workbox
.
vous pouvez l'importer dans votre code depuis notre CDN ou à l'aide de l'une des
Outils de regroupement JavaScript.
Utiliser notre CDN
Le moyen le plus simple d'importer la classe Workbox
sur votre site consiste à utiliser notre CDN:
<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>
Notez que cet exemple utilise <script type="module">
et l'instruction import
pour
charger la classe Workbox
. Même si vous pensez peut-être que vous devez
pour qu'elle fonctionne dans des navigateurs
plus anciens, ce n'est en fait pas nécessaire.
Tous les principaux navigateurs compatibles avec le service workers sont également compatibles avec les modules JavaScript natifs. C'est donc parfaitement Vous pouvez diffuser ce code dans tous les navigateurs (les anciens navigateurs l'ignoreront).
Chargement de Workbox avec des bundlers JavaScript
Bien qu'aucun outil ne soit requis pour utiliser workbox-window
, si votre
l'infrastructure de développement
inclut déjà un bundler comme
webpack ou Rollup qui fonctionne
avec des dépendances npm, il est possible de les utiliser pour
charger workbox-window
.
La première étape consiste à
installer
workbox-window
en tant que dépendance de votre application:
npm install workbox-window
Ensuite, dans l'un des fichiers JavaScript de votre application, la boîte de travail import
en faisant référence au nom du package workbox-window
:
import {Workbox} from 'workbox-window';
if ('serviceWorker' in navigator) {
const wb = new Workbox('/sw.js');
wb.register();
}
Si votre bundler accepte le scission du code via des instructions d'importation dynamique,
vous pouvez également charger workbox-window
de manière conditionnelle, ce qui devrait réduire le
la taille du groupe principal de votre page.
Même si workbox-window
est assez petit, il n'y a aucune raison qu'il
doit être chargé avec la logique d'application de base de votre site, en tant que service workers,
par leur nature même, sont une amélioration progressive.
if ('serviceWorker' in navigator) {
const {Workbox} = await import('workbox-window');
const wb = new Workbox('/sw.js');
wb.register();
}
Concepts avancés de regroupement
Contrairement aux packages Workbox qui s'exécutent dans le service worker, les fichiers de compilation
référencées par workbox-window
main
et
module
champs dans
Les package.json
sont transcompilées dans ES5. Elles sont ainsi compatibles avec
des outils de compilation, dont certains ne permettent pas aux développeurs de transposer quoi que ce soit
leurs dépendances node_module
.
Si votre système de compilation vous permet bien de transpiler vos dépendances (ou si vous vous n'avez pas besoin de transpiler votre code), il est préférable d'importer un fichier fichier source plutôt que le package lui-même.
Voici les différentes façons d'importer Workbox
, ainsi qu'une explication des
ce que chacun renverra:
// 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';
Exemples
Une fois la classe Workbox
importée, vous pouvez l'utiliser pour enregistrer et
avec votre service worker. Voici quelques exemples d'utilisation
Workbox
dans votre application:
Enregistrer un service worker et avertir l'utilisateur la première fois qu'il est actif
De nombreuses applications Web utilisent un service worker de mettre en cache les éléments en amont afin que leur application fonctionne. hors ligne lors des chargements de page suivants. Dans certains cas, il peut être judicieux d’informer que l'application est désormais disponible hors connexion.
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();
Informer l'utilisateur si un service worker a été installé, mais reste bloqué dans l'attente d'activation
Lorsqu'une page contrôlée par un service worker existant enregistre un nouveau service. par défaut, le service worker ne s'active pas tant que tous les clients par le service worker initial sont entièrement déchargées.
Il s'agit d'une source de confusion courante pour les développeurs, en particulier dans les cas où L'actualisation de la page actuelle n'entraîne pas l'activation du nouveau service worker.
Pour aider à minimiser la confusion et
indiquer clairement quand cette situation se produit,
La classe Workbox
fournit un événement waiting
que vous pouvez écouter:
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();
Informer l'utilisateur des mises à jour du cache à partir du package workbox-broadcast-update
Le package workbox-broadcast-update
est un excellent moyen de diffuser du contenu à partir du cache (pour une distribution rapide), tout en
informer l'utilisateur des modifications apportées à ce contenu (à l'aide de la méthode
stratégie de type "stale-while-revalidate").
Pour recevoir ces mises à jour à partir de la fenêtre, vous pouvez écouter les événements message
de
Type 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();
Envoyer au service worker la liste des URL à mettre en cache
Pour certaines applications, il est possible de connaître tous les éléments qui doivent être en pré-cache lors de la compilation, mais certaines applications affichent des pages complètement différentes, en fonction de l'URL à laquelle l'utilisateur arrive en premier.
Pour les applications appartenant à cette dernière catégorie, il peut être judicieux de ne mettre en cache que les éléments.
l'utilisateur avait besoin pour
la page spécifique qu'il a consultée. Lorsque vous utilisez la
package workbox-routing
, vous pouvez
envoyer à votre routeur une liste d'URL à mettre en cache, qui les mettra en cache selon
aux règles définies sur le routeur lui-même.
Cet exemple envoie une liste des URL chargées par la page au routeur chaque fois qu'un un nouveau service worker est activé. Notez que vous pouvez envoyer toutes les URL, car seules les URL qui correspondent à une route définie dans le service worker sont mises en cache:
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();
Moments importants dans le cycle de vie d'un service worker
Cycle de vie d'un service worker est complexe et peut être difficile à comprendre. Cela explique en partie est si complexe qu'il doit gérer tous les cas limites pour toutes les utilisations possibles (par exemple, l'enregistrement de plusieurs service worker, l'enregistrement service worker dans des trames différentes, en enregistrant les service workers avec noms différents, etc.).
Toutefois, la plupart des développeurs qui implémentent un service worker n'ont pas à se soucier tous ces cas limites, car leur utilisation est assez simple. La plupart des développeurs n'enregistrent qu'un seul service worker par chargement de page et ne modifient pas le nom du service worker. qu'ils déploient sur leur serveur.
La classe Workbox
adopte cette vue simplifiée pour le cycle de vie d'un service worker
en divisant tous les enregistrements de service workers en deux catégories :
un service worker enregistré et un service worker externe:
- Service worker enregistré: service worker dont l'installation a été lancée en tant que service worker
résultat de l'instance
Workbox
qui appelleregister()
ou l'appel de la fonction service worker si l'appel deregister()
n'a pas déclenché d'événementupdatefound
lors de l'enregistrement. - Service worker externe:service worker qui a démarré l'installation
indépendamment de l'instance
Workbox
qui appelleregister()
. Il s'agit généralement se produit lorsqu'un utilisateur ouvre une nouvelle version de votre site dans un autre onglet. Lorsqu'un l'événement provient d'un service worker externe, leisExternal
de l'événement. est définie surtrue
.
En gardant à l'esprit ces deux types de service workers, voici une répartition de toutes les moments importants du cycle de vie d'un service worker, ainsi que les recommandations pour les développeurs pour savoir comment les gérer:
La toute première fois qu'un service worker est installé.
La toute première installation d'un service worker de la façon dont vous traitez les futures mises à jour.
Dans workbox-window
, vous pouvez d'abord différencier la version
l'installation et les mises à jour futures en vérifiant la propriété isUpdate
sur l'une des
les événements suivants. Pour la toute première installation, isUpdate
sera
false
const wb = new Workbox('/sw.js');
wb.addEventListener('installed', event => {
if (!event.isUpdate) {
// First-installed code goes here...
}
});
wb.register();
Lorsqu'une version mise à jour du service worker est détectée.
Lorsqu'un nouveau service worker commence à s'installer, mais qu'une version existante est en cours d'installation
la propriété isUpdate
de tous les événements suivants
définie sur true
.
Votre réaction dans cette situation est généralement différente de la toute première car vous devez gérer quand et comment l’utilisateur reçoit cette mise à jour.
Lorsqu'une version inattendue du service worker est détectée
Parfois, les utilisateurs gardent votre site ouvert dans un onglet en arrière-plan très longtemps en temps réel. Ils pourraient même ouvrir un nouvel onglet et accéder à votre site sans s'en rendre compte votre site est déjà ouvert dans un onglet en arrière-plan. Dans ce cas, il est que deux versions de votre site peuvent s'exécuter en même temps peut présenter des problèmes intéressants pour vous en tant que développeur.
Imaginez que l'onglet A exécute la version 1 de votre site et l'onglet B exécutant la version 2. Le chargement de l'onglet B est contrôlé par la version de votre service fourni avec la version 1, mais la page renvoyée par le serveur (si vous utilisez un stratégie de mise en cache axée sur le réseau pour vos demandes de navigation) contient tous les éléments de la version 2.
Ce n'est généralement pas un problème pour l'onglet B, car lorsque vous avez écrit votre version 2 vous saviez comment fonctionnait votre code v1. Il peut toutefois s'agir pour l'onglet A,car le code de la version 1 n'aurait pas pu prédire que votre code de la version 2 pourrait introduire.
Pour vous aider à gérer ces situations, workbox-window
déclenche également le cycle de vie
lorsqu'il détecte une mise à jour provenant d'une service worker, où
"external" signifie que toute version autre que celle de la Workbox
actuelle
enregistrée.
À partir de la version 6 de Workbox v6, ces événements équivalent aux événements documentés
ci-dessus, avec l'ajout d'une propriété isExternal: true
définie pour chaque événement
. Si votre application Web doit implémenter une logique spécifique pour gérer une
externe vous pouvez rechercher cette propriété dans vos gestionnaires d'événements.
Éviter les erreurs courantes
L'une des fonctionnalités les plus utiles de Workbox est la journalisation pour les développeurs. Et
c'est particulièrement vrai pour workbox-window
.
Nous savons que le développement avec un service worker peut être source de confusion. se produire contrairement à ce à quoi vous vous attendiez, il peut être difficile de savoir pourquoi.
Par exemple, lorsque vous apportez une modification à votre service worker et que vous actualisez la page, vous ne verrez peut-être pas ce changement dans votre navigateur. La raison la plus probable de ce phénomène, si votre service worker est toujours en attente d'activation.
Toutefois, lorsque vous enregistrez un service worker avec la classe Workbox
, vous êtes
informée de tous les changements d'état du cycle de vie dans la Play Console, ce qui devrait
vous aidera à déboguer pourquoi les choses
ne sont pas comme prévu.
Les développeurs commettent souvent l'erreur qu'ils font lorsqu'ils utilisent un service worker pour la première fois : pour enregistrer un service worker Champ d'application incorrect.
Pour éviter que cela ne se produise, la classe Workbox
vous avertit si l'élément
qui enregistre le service worker n'entre pas dans le champ d'application de ce service worker. Il va
Vous recevez également un avertissement lorsque votre service worker est actif, mais pas encore.
pour contrôler la page:
Communication entre la fenêtre et le service worker
L'utilisation la plus avancée d'un service worker implique une grande quantité de messages entre les
le service worker et la fenêtre. La classe Workbox
permet également d'y parvenir en
en fournissant une méthode messageSW()
, qui va postMessage()
à l'instance
service worker enregistré et attendre une réponse.
Vous pouvez envoyer des données au service worker sous n'importe quel format, mais ce format partageait de tous les packages Workbox est un objet doté de trois propriétés (ces deux dernières étant facultative):
Les messages envoyés via la méthode messageSW()
utilisent MessageChannel
afin que le destinataire
peuvent y répondre. Pour répondre à un message, vous pouvez appeler
event.ports[0].postMessage(response)
dans votre écouteur d'événements de message. La
La méthode messageSW()
renvoie une promesse qui sera résolue par l'élément response
avec lequel vous répondez.
Voici un exemple d'envoi de messages au service worker depuis la fenêtre
obtenir une réponse. Le premier bloc de code est l'écouteur de message dans
service worker, et le deuxième bloc utilise la classe Workbox
pour envoyer le
message et attendez la réponse:
Code dans sw.js:
const SW_VERSION = '1.0.0';
addEventListener('message', event => {
if (event.data.type === 'GET_VERSION') {
event.ports[0].postMessage(SW_VERSION);
}
});
Code dans main.js (s'exécutant dans la fenêtre):
const wb = new Workbox('/sw.js');
wb.register();
const swVersion = await wb.messageSW({type: 'GET_VERSION'});
console.log('Service Worker version:', swVersion);
Gérer les incompatibilités de versions
L'exemple ci-dessus montre comment mettre en œuvre la vérification du service worker dans la fenêtre. Cet exemple est utilisé, car lorsque vous envoyez entre la fenêtre et le service worker, il est essentiel que votre service worker n'exécute peut-être pas la même version sur votre site que le code de votre page est exécuté, et la solution pour y remédier varie selon que vous diffusez vos pages en priorité ou mise en cache.
Priorité au réseau
Lorsqu'ils diffusent en premier votre réseau de pages, vos utilisateurs bénéficient toujours la dernière version de votre code HTML sur votre serveur. Toutefois, la première fois qu'un utilisateur revient sur votre site (après avoir déployé une mise à jour), le code HTML obtenu sera pour la dernière version, mais le service worker qui s'exécute dans son navigateur sera une version déjà installée (peut-être de nombreuses versions anciennes) ;
Il est important de comprendre cette possibilité, car si JavaScript chargeait à la version actuelle de votre page envoie un message à une ancienne version service worker, il est possible que cette version ne sache pas comment répondre (ou qu'elle envoie une réponse format incompatible).
Par conséquent, il est recommandé de toujours gérer les versions de votre service worker et de vérifier pour connaître les versions compatibles avant d'effectuer tout travail critique.
Par exemple, dans le code ci-dessus, si la version de service worker renvoyée par ce
L'appel messageSW()
est antérieur à la version attendue, il est conseillé d'attendre
jusqu'à ce qu'une mise à jour soit trouvée (ce qui devrait se produire lorsque vous appelez register()
). À
vous pouvez soit informer l'utilisateur de la mise à jour, soit en informer l'utilisateur
ignorer la phase d'attente
pour activer immédiatement le nouveau service worker.
Mettre en cache d'abord
Contrairement au cas où vous diffusez vos pages en priorité réseau,
Tout d'abord, vous savez que, au départ, votre page sera toujours la même version que
votre service worker (car c'est ce qui l'a diffusé). Par conséquent, il est sécurisé
pour utiliser messageSW()
immédiatement.
Toutefois, si une version mise à jour de votre service worker est détectée et s'active
Lorsque votre page appelle register()
(vous ignorez intentionnellement la phase d'attente),
vous ne pourrez peut-être plus lui envoyer de messages en toute sécurité.
Une stratégie pour gérer cette possibilité consiste à utiliser un schéma de gestion des versions qui vous permet de distinguer les mises à jour destructives des mises à jour non destructives, Dans le cas d'une mise à jour destructive, vous savez qu'il n'est pas prudent d'envoyer un message un service worker. Au lieu de cela, vous devez avertir l'utilisateur qu'il exécute une ancienne de la page et lui suggérez de l'actualiser pour obtenir la mise à jour.
Ignorer l'aide en attente
Une convention d'utilisation courante de la messagerie pour les agents de fenêtre à service est l'envoi d'un
Message {type: 'SKIP_WAITING'}
demandant à un service worker installé de procéder à
ignorer la phase d'attente
puis activez-la.
À partir de Workbox v6, la méthode messageSkipWaiting()
permet d'envoyer un
{type: 'SKIP_WAITING'}
envoyé au service worker en attente associé au
l'enregistrement actuel du service worker. En l'absence de signal sonore, il n'a aucun effet
en attente.
Types
Workbox
Une classe facilitant la gestion de l'enregistrement, des mises à jour et des aux événements de cycle de vie d'un service worker.
Propriétés
-
constructor
vide
Crée une instance Workbox avec une URL de script et un service worker options. L'URL et les options de script sont les mêmes que celles utilisées lorsque navigator.serviceWorker.register(scriptURL, options)
La fonction
constructor
se présente comme suit:(scriptURL: string | TrustedScriptURL, registerOptions?: object) => {...}
-
scriptURL
string | TrustedScriptURL
Script de service worker associées à cette instance. Avec un
TrustedScriptURL
est compatible. -
registerOptions
objet facultatif
-
retours
-
-
actif
Promise<ServiceWorker>
-
contrôler
Promise<ServiceWorker>
-
getSW
vide
Résout avec une référence à un service worker correspondant à l'URL du script de cette instance dès qu'elle sera disponible.
Si, au moment de l'enregistrement, un service est déjà actif ou en attente associé à une URL de script correspondante, celui-ci sera utilisé (avec le paramètre le service worker prévaut sur le service worker actif si les deux car le service worker en attente aurait été enregistré plus récemment). Si aucun service worker correspondant n'est actif ou en attente au moment de l'enregistrement la promesse ne se résoudra pas tant qu'une mise à jour n'aura pas été trouvée et lancée l'installation. Le service worker d'installation est alors utilisé.
La fonction
getSW
se présente comme suit:() => {...}
-
retours
Promise<ServiceWorker>
-
-
messageSW
vide
Envoie l'objet de données transmis au service worker enregistré par (via
workbox-window.Workbox#getSW
) et résout avec une réponse (le cas échéant).Une réponse peut être définie dans un gestionnaire de messages du service worker en en appelant
event.ports[0].postMessage(...)
, ce qui résout la promesse ; renvoyé parmessageSW()
. Si aucune réponse n'est définie, la promesse résoudre.La fonction
messageSW
se présente comme suit:(data: object) => {...}
-
données
objet
Objet à envoyer au service worker
-
retours
Promesse<tous>
-
-
messageSkipWaiting
vide
Elle envoie un message
{type: 'SKIP_WAITING'}
au service worker qui est dont l'état est actuellementwaiting
associé à l'enregistrement actuel.En l'absence d'enregistrement ou si aucun service worker n'est défini sur
waiting
, appeler ceci n'aura aucun effet.La fonction
messageSkipWaiting
se présente comme suit:() => {...}
-
register
vide
Enregistre un service worker pour l'URL de script et le service de cette instance les options de nœud de calcul. Par défaut, cette méthode retarde l'enregistrement jusqu'au la fenêtre est chargée.
La fonction
register
se présente comme suit:(options?: object) => {...}
-
options
objet facultatif
-
à proximité immédiate
Booléen facultatif
-
-
retours
Promise<ServiceWorkerRegistration>
-
-
update
vide
Recherche les mises à jour du service worker enregistré.
La fonction
update
se présente comme suit:() => {...}
-
retours
Promesse<void>
-
WorkboxEventMap
Propriétés
-
Activé
-
activation...
-
contrôler
-
application installée
-
installer
-
message
-
redondant
-
en attente
WorkboxLifecycleEvent
Propriétés
-
isExternal
Booléen facultatif
-
isUpdate
Booléen facultatif
-
originalEvent
Événement facultatif
-
sw
ServiceWorker facultatif
-
cible
WorkboxEventTarget facultatif
-
type
typeOperator
WorkboxLifecycleEventMap
Propriétés
-
Activé
-
activation...
-
contrôler
-
application installée
-
installer
-
redondant
-
en attente
WorkboxLifecycleWaitingEvent
Propriétés
-
isExternal
Booléen facultatif
-
isUpdate
Booléen facultatif
-
originalEvent
Événement facultatif
-
sw
ServiceWorker facultatif
-
cible
WorkboxEventTarget facultatif
-
type
typeOperator
-
wasWaitingBeforeRegister
Booléen facultatif
WorkboxMessageEvent
Propriétés
-
données
tous
-
isExternal
Booléen facultatif
-
originalEvent
Événement
-
ports
typeOperator
-
sw
ServiceWorker facultatif
-
cible
WorkboxEventTarget facultatif
-
type
"message"
Méthodes
messageSW()
workbox-window.messageSW(
sw: ServiceWorker,
data: object,
)
Envoie un objet de données à un service worker via postMessage
et se résout avec
une réponse (le cas échéant).
Une réponse peut être définie dans un gestionnaire de messages du service worker en
en appelant event.ports[0].postMessage(...)
, ce qui résout la promesse ;
renvoyé par messageSW()
. Si aucune réponse n'est définie, la promesse
résoudre.
Paramètres
-
sw
ServiceWorker
Service worker auquel le message doit être envoyé.
-
données
objet
Objet à envoyer au service worker.
Renvoie
-
Promesse<tous>