Guide du débutant sur l'utilisation du cache d'application

Introduction

Il est de plus en plus important que les applications Web soient accessibles hors connexion. Oui, tous les navigateurs peuvent mettre en cache les pages et les ressources pendant de longues périodes s'ils le font. Toutefois, le navigateur peut à tout moment exclure certains éléments du cache afin de libérer de l'espace pour d'autres éléments. Le format HTML5 résout certains problèmes liés à la déconnexion via l'interface ApplicationCache. L'utilisation de l'interface de cache offre à votre application trois avantages:

  1. Navigation hors connexion : les utilisateurs peuvent parcourir l'ensemble de votre site lorsqu'ils ne sont pas connectés à Internet.
  2. Vitesse : les ressources proviennent directement du disque, pas de trajet vers le réseau.
  3. Résilience : si votre site est en panne pour cause de maintenance (par exemple, si quelqu'un casse tout accidentellement), vos utilisateurs bénéficieront d'une expérience hors connexion.

Le cache d'application (ou AppCache) permet à un développeur de spécifier les fichiers que le navigateur doit mettre en cache et rendre disponibles aux utilisateurs hors connexion. Votre application se chargera et fonctionnera correctement, même si l'utilisateur appuie sur le bouton d'actualisation lorsqu'il est hors connexion.

Fichier manifeste du cache

Le fichier manifeste de cache est un simple fichier texte qui répertorie les ressources que le navigateur doit mettre en cache pour un accès hors connexion.

Référencer un fichier manifeste

Pour activer le cache d'application pour une application, incluez l'attribut de fichier manifeste dans la balise html du document:

<html manifest="example.appcache">
  ...
</html>

L'attribut manifest doit être inclus sur chaque page de votre application Web que vous souhaitez mettre en cache. Le navigateur ne met pas en cache une page si elle ne contient pas l'attribut manifest (sauf s'il est explicitement indiqué dans le fichier manifeste lui-même. Cela signifie que toute page à laquelle l'utilisateur accède et qui inclut un manifest sera implicitement ajoutée au cache de l'application. Il n'est donc pas nécessaire de répertorier toutes les pages de votre fichier manifeste. Si une page renvoie vers un fichier manifeste, il est impossible d'empêcher sa mise en cache.

Vous pouvez consulter les URL contrôlées par le cache de l'application en accédant à about://appcache-internals/ dans Chrome. Vous pouvez alors vider les caches et afficher les entrées. Il existe des outils de développement similaires dans Firefox.

L'attribut manifest peut pointer vers une URL absolue ou un chemin relatif, mais une URL absolue doit se trouver sous la même origine que l'application Web. Un fichier manifeste peut avoir n'importe quelle extension, mais doit être diffusé avec le type MIME approprié (voir ci-dessous).

<html manifest="http://www.example.com/example.mf">
  ...
</html>

Un fichier manifeste doit être diffusé avec le type MIME text/cache-manifest. Vous devrez peut-être ajouter un type de fichier personnalisé à votre serveur Web ou à la configuration .htaccess.

Par exemple, pour diffuser ce type MIME dans Apache, ajoutez la ligne suivante à votre fichier de configuration:

AddType text/cache-manifest .appcache

Vous pouvez également accéder à votre fichier app.yaml dans Google App Engine:

- url: /mystaticdir/(.*\.appcache)
  static_files: mystaticdir/\1
  mime_type: text/cache-manifest
  upload: mystaticdir/(.*\.appcache)

Cette exigence a été supprimée de la spécification il y a quelque temps et n'est plus requise dans les dernières versions de Chrome, Safari et Firefox. Toutefois, vous aurez besoin du type MIME pour fonctionner dans des navigateurs plus anciens et IE11.

Structure d'un fichier manifeste

Il s'agit d'un fichier distinct vers lequel vous fournissez un lien via l'attribut de fichier manifeste dans l'élément HTML. Un fichier manifeste simple ressemble à ceci:

CACHE MANIFEST
index.html
stylesheet.css
images/logo.png
scripts/main.js
http://cdn.example.com/scripts/main.js

Cet exemple met en cache quatre fichiers sur la page spécifiant ce fichier manifeste.

Voici quelques points à noter:

  • La chaîne CACHE MANIFEST est la première ligne et est obligatoire.
  • Les fichiers peuvent provenir d'un autre domaine
  • Certains navigateurs imposent des restrictions sur le quota de stockage disponible pour votre application. Dans Chrome, par exemple, AppCache utilise un pool partagé d'espace de stockage TEMPORAIRE que d'autres API hors connexion peuvent partager. Si vous développez une application pour le Chrome Web Store, l'utilisation de unlimitedStorage permet de supprimer cette restriction.
  • Si le fichier manifeste renvoie un code 404 ou 410, le cache est supprimé.
  • En cas d'échec du téléchargement du fichier manifeste ou d'une ressource spécifiée, l'ensemble du processus de mise à jour du cache échoue. Le navigateur continuera d'utiliser le cache de l'ancienne application en cas d'échec.

Examinons un exemple plus complexe:

CACHE MANIFEST
# 2010-06-18:v2

# Explicitly cached 'master entries'.
CACHE:
/favicon.ico
index.html
stylesheet.css
images/logo.png
scripts/main.js

# Resources that require the user to be online.
NETWORK:
*

# static.html will be served if main.py is inaccessible
# offline.jpg will be served in place of all images in images/large/
# offline.html will be served in place of all other .html files
FALLBACK:
/main.py /static.html
images/large/ images/offline.jpg

Les lignes qui commencent par "#" sont des lignes de commentaire, mais elles peuvent également servir à d'autres fins. Le cache d'une application n'est mis à jour que lorsque son fichier manifeste change. Ainsi, par exemple, si vous modifiez une ressource d'image ou une fonction JavaScript, ces modifications ne seront pas remises en cache. Vous devez modifier le fichier manifeste lui-même pour indiquer au navigateur d'actualiser les fichiers mis en cache.

Évitez d'utiliser un horodatage continuellement mis à jour ou une chaîne aléatoire pour forcer les mises à jour à chaque fois. Le fichier manifeste est vérifié deux fois lors d'une mise à jour : une fois au début et une fois après la mise à jour de tous les fichiers mis en cache. Si le fichier manifeste a changé lors de la mise à jour, il est possible que le navigateur ait récupéré certains fichiers d'une version et d'autres d'une autre version. Il n'applique donc pas le cache et retente ultérieurement.

Le cache est mis à jour, mais le navigateur n'utilise pas ces fichiers tant que la page n'a pas été actualisée. En effet, les mises à jour ont lieu après le chargement de la page à partir de la version actuelle du cache.

Un fichier manifeste peut comporter trois sections distinctes: CACHE, NETWORK et FALLBACK.

CACHE:
Il s'agit de la section par défaut pour les entrées. Les fichiers répertoriés sous cet en-tête (ou immédiatement après CACHE MANIFEST) seront explicitement mis en cache après leur premier téléchargement. NETWORK:
Les fichiers listés dans cette section peuvent provenir du réseau s'ils ne sont pas dans le cache. Sinon, le réseau n'est pas utilisé, même si l'utilisateur est en ligne. Vous pouvez ajouter des URL spécifiques à la liste blanche ici ou simplement "", pour autoriser toutes les URL. La plupart des sites ont besoin de "". FALLBACK:
Section facultative spécifiant les pages de remplacement lorsqu'une ressource est inaccessible. Le premier URI est la ressource, et le second est la solution de secours utilisée en cas d'échec ou d'erreur de la requête réseau. Les deux URI doivent avoir la même origine que le fichier manifeste. Vous pouvez capturer des URL spécifiques, mais également des préfixes d'URL. "images/large/" capture les échecs à partir des URL telles que "images/large/whatever/img.jpg".

Le fichier manifeste suivant définit une page "catch-all" (offline.html) qui s'affiche lorsque l'utilisateur tente d'accéder à la racine du site hors connexion. Il déclare également que toutes les autres ressources (par exemple, celles qui se trouvent sur un site distant) nécessitent une connexion Internet.

CACHE MANIFEST
# 2010-06-18:v3

# Explicitly cached entries
index.html
css/style.css

# offline.html will be displayed if the user is offline
FALLBACK:
/ /offline.html

# All other resources (e.g. sites) require the user to be online.
NETWORK:
*

# Additional resources to cache
CACHE:
images/logo1.png
images/logo2.png
images/logo3.png

Mise à jour du cache

Une fois qu'une application est hors connexion, elle reste mise en cache jusqu'à ce qu'un des événements suivants se produise:

  1. L'utilisateur efface l'espace de stockage des données de son navigateur pour votre site.
  2. Le fichier manifeste a été modifié. Remarque: La mise à jour d'un fichier répertorié dans le fichier manifeste ne signifie pas que le navigateur mettra à nouveau la ressource en cache. Le fichier manifeste lui-même doit être modifié.

État du cache

L'objet window.applicationCache correspond à votre accès programmatique au cache d'applications du navigateur. Sa propriété status permet de vérifier l'état actuel du cache:

var appCache = window.applicationCache;

switch (appCache.status) {
case appCache.UNCACHED: // UNCACHED == 0
return 'UNCACHED';
break;
case appCache.IDLE: // IDLE == 1
return 'IDLE';
break;
case appCache.CHECKING: // CHECKING == 2
return 'CHECKING';
break;
case appCache.DOWNLOADING: // DOWNLOADING == 3
return 'DOWNLOADING';
break;
case appCache.UPDATEREADY:  // UPDATEREADY == 4
return 'UPDATEREADY';
break;
case appCache.OBSOLETE: // OBSOLETE == 5
return 'OBSOLETE';
break;
default:
return 'UKNOWN CACHE STATUS';
break;
};

Pour rechercher de manière programmatique les mises à jour du fichier manifeste, appelez d'abord applicationCache.update(). Cette action va tenter de mettre à jour le cache de l'utilisateur (ce qui nécessite une modification du fichier manifeste). Enfin, lorsque applicationCache.status présente l'état UPDATEREADY, l'appel de applicationCache.swapCache() remplace l'ancien cache par le nouveau.

var appCache = window.applicationCache;

appCache.update(); // Attempt to update the user's cache.

...

if (appCache.status == window.applicationCache.UPDATEREADY) {
appCache.swapCache();  // The fetch was successful, swap in the new cache.
}

La bonne nouvelle, c'est que vous pouvez automatiser ce processus. Pour mettre à jour les utilisateurs vers la dernière version de votre site, configurez un écouteur afin de surveiller l'événement updateready lors du chargement de la page:

// Check if a new cache is available on page load.
window.addEventListener('load', function(e) {

window.applicationCache.addEventListener('updateready', function(e) {
if (window.applicationCache.status == window.applicationCache.UPDATEREADY) {
    // Browser downloaded a new app cache.
    if (confirm('A new version of this site is available. Load it?')) {
    window.location.reload();
    }
} else {
    // Manifest didn't changed. Nothing new to server.
}
}, false);

}, false);

Événements AppCache

Comme vous pouvez vous y attendre, des événements supplémentaires sont exposés pour surveiller l'état du cache. Le navigateur déclenche des événements tels que la progression du téléchargement, la mise à jour du cache de l'application et les conditions d'erreur. L'extrait de code suivant configure des écouteurs d'événements pour chaque type d'événement de cache:

function handleCacheEvent(e) {
//...
}

function handleCacheError(e) {
alert('Error: Cache failed to update!');
};

// Fired after the first cache of the manifest.
appCache.addEventListener('cached', handleCacheEvent, false);

// Checking for an update. Always the first event fired in the sequence.
appCache.addEventListener('checking', handleCacheEvent, false);

// An update was found. The browser is fetching resources.
appCache.addEventListener('downloading', handleCacheEvent, false);

// The manifest returns 404 or 410, the download failed,
// or the manifest changed while the download was in progress.
appCache.addEventListener('error', handleCacheError, false);

// Fired after the first download of the manifest.
appCache.addEventListener('noupdate', handleCacheEvent, false);

// Fired if the manifest file returns a 404 or 410.
// This results in the application cache being deleted.
appCache.addEventListener('obsolete', handleCacheEvent, false);

// Fired for each resource listed in the manifest as it is being fetched.
appCache.addEventListener('progress', handleCacheEvent, false);

// Fired when the manifest resources have been newly redownloaded.
appCache.addEventListener('updateready', handleCacheEvent, false);

En cas d'échec du téléchargement du fichier manifeste ou d'une ressource spécifiée, la mise à jour complète échoue. En cas d'échec, le navigateur continuera d'utiliser le cache de l'ancienne application.

Références