Concepts avancés
Service workers
Éditer cette page sur GithubLes service workers sont des scripts qui jouent le rôle de proxy afin de gérer les requêtes réseau au sein de votre application. Cela rend possible le fonctionnement hors-ligne de votre application, mais même si vous n'avez pas besoin d'un support hors-ligne (ou si vous ne pouvez pas vraiment l'implémenter à cause du type d'application que vous développez), il est souvent pertinent d'utiliser des service workers pour accélérer la navigation en mettant en cache de manière anticipée votre JS et votre CSS.
Dans SvelteKit, si vous avez un fichier src/service-worker.js
(ou src/service-worker/index.js
), celui-ci sera compilé et automatiquement activé. Vous pouvez modifier l'emplacement de votre service worker si nécessaire.
Vous pouvez désactiver l'activation automatique si vous souhaitez activer le service worker selon votre propre logique ou utiliser une autre solution. L'activation par défaut ressemble à quelque chose comme ça :
ts
if ('serviceWorker' innavigator ) {addEventListener ('load', function () {navigator .serviceWorker .register ('./path/to/service-worker.js');});}
À l'intérieur du service workerpermalink
Au sein du service worker, vous avez accès au module $service-worker
, qui vous fournit les chemins de tous les fichiers statiques, fichiers compilés et pages prérendues. Vous avez également accès à la chaîne de caractères représentant la version de votre application, que vous pouvez utiliser pour créer un nom de cache unique, ainsi qu'au chemin de base
du déploiement. Si votre configuration Vite précise l'option define
(utilisée pour les remplacements de variables globales), celle-ci sera appliquée à vos service workers ainsi qu'à vos builds serveur/client.
L'exemple suivant met en cache immédiatement l'application compilée ainsi que tout fichier du dossier static
, et met toutes les autres requêtes en cache au fur et à mesure qu'elles se produisent. Cela permet de rendre disponible chaque page en hors-ligne après une première visite.
ts
/// <reference types="@sveltejs/kit" />import {build ,files ,version } from '$service-worker';// Crée un nom de cache unique pour ce déploiementconstCACHE = `cache-${version }`;constASSETS = [...build , // l'application elle-même...files // tout ce qu'il y a dans 'static'];self .addEventListener ('install', (event ) => {// Crée un nouveau cache et y ajoute tous les fichiersasync functionaddFilesToCache () {constProperty 'waitUntil' does not exist on type 'Event'.2339Property 'waitUntil' does not exist on type 'Event'.cache = awaitcaches .open (CACHE );awaitcache .addAll (ASSETS );}event .waitUntil (addFilesToCache ());});self .addEventListener ('activate', (event ) => {// Remove previous cached data from diskasync functiondeleteOldCaches () {for (constkey of awaitcaches .keys ()) {if (Property 'waitUntil' does not exist on type 'Event'.2339Property 'waitUntil' does not exist on type 'Event'.key !==CACHE ) awaitcaches .delete (key );}}event .waitUntil (deleteOldCaches ());});Property 'request' does not exist on type 'Event'.2339Property 'request' does not exist on type 'Event'.self .addEventListener ('fetch', (event ) => {// ignore les requêtes POST etcProperty 'request' does not exist on type 'Event'.2339Property 'request' does not exist on type 'Event'.if (event .request .method !== 'GET') return;async functionrespond () {consturl = newURL (event .request .url );constcache = awaitcaches .open (CACHE );// `build`/`files` peuvent toujours être servis depuis le cacheif (ASSETS .includes (url .pathname )) {constresponse = awaitcache .match (url .pathname );if (response ) {returnresponse ;}}Property 'request' does not exist on type 'Event'.2339Property 'request' does not exist on type 'Event'.// pour tout le reste, commence par essayer le réseau,// mais utilise le cache si nous sommes hors-lignetry {constresponse = awaitfetch (event .request );// if we're offline, fetch can return a value that is not a Response// instead of throwing - and we can't pass this non-Response to respondWithif (!(response instanceofResponse )) {throw newProperty 'request' does not exist on type 'Event'.2339Property 'request' does not exist on type 'Event'.Error ('invalid response from fetch'); }if (response .status === 200) {cache .put (event .request ,response .clone ());}Property 'request' does not exist on type 'Event'.2339Property 'request' does not exist on type 'Event'.returnresponse ;} catch (err ) {constresponse = awaitcache .match (event .request );if (response ) {returnresponse ;}// if there's no cache, then just error out// as there is nothing we can do to respond to this requestthrowProperty 'respondWith' does not exist on type 'Event'.2339Property 'respondWith' does not exist on type 'Event'.err ;}}event .respondWith (respond ());});
Soyez vigilant•e•s lorsque vous mettez en cache ! Dans certains cas, afficher des données périmées peut être plus problématique que ne pas afficher de données si vous être hors-ligne. De plus, puisque les navigateurs vident leur cache si celui-ci se remplit trop, vous devriez également faire attention lorsque vous choisissez de mettre en cache de gros fichiers comme des vidéos.
Pendant le développementpermalink
Les service workers sont utilisés pour la production, mais pas pendant le développement. Pour cette raison, seuls les navigateurs qui supportent les modules dans les service workers (en anglais) seront capables de les utiliser pendant que vous développez. Si vous activez manuellement votre service worker, vous aurez besoin d'utiliser l'option { type: 'module' }
pendant le développement :
ts
import {dev } from '$app/environment';navigator .serviceWorker .register ('/service-worker.js', {type :dev ? 'module' : 'classic'});
build
etprerendered
sont des tableaux vides pendant le développement
Typagepermalink
Mettre en place un typage correct pour les service workers nécessite un peu de préparation manuelle. Dans votre fichier service-worker.js
, ajoutez ce qui suit en haut de votre fichier :
ts
/// <reference types="@sveltejs/kit" />/// <reference no-default-lib="true"/>/// <reference lib="esnext" />/// <reference lib="webworker" />constsw = /** @type {ServiceWorkerGlobalScope} */ (/** @type {unknown} */ (self ));
ts
/// <reference types="@sveltejs/kit" />/// <reference no-default-lib="true"/>/// <reference lib="esnext" />/// <reference lib="webworker" />constsw =self as unknown asServiceWorkerGlobalScope ;
Ceci désactive l'accès aux types du DOM comme HTMLElement
qui ne sont pas disponibles dans un service worker, et instancie les bonnes variables globales. La réassignation de self
en sw
vous permet également de lui assigner le bon type (il y a plusieurs moyens pour faire cela, mais celui-ci est le plus simple sans rajouter de fichier). Utilisez sw
au lieu de self
dans le reste de votre fichier. La référence aux types de SvelteKit assure que l'import de $service-worker
est correctement typé.
Autres solutionspermalink
L'implémentation des service workers dans SvelteKit est délibérément bas niveau. Si vous avez besoin d'une solution plus clé-en-main, nous vous recommandons de vous tourner vers le plugin Vite PWA, qui utilise Workbox. Pour plus d'informations sur les service workers, nous vous recommandons de lire la documentation de MDN sur le sujet.