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 des pages et des ressources pendant de longues périodes s'ils sont invités à le faire. Cependant, le navigateur peut à tout moment retirer des éléments du cache afin de libérer de la place pour d'autres éléments. Le HTML5 résout certains des inconvénients liés au fait d'être hors connexion avec l'interface ApplicationCache. L'utilisation de l'interface de cache offre trois avantages à votre application:

  1. Navigation hors connexion : les utilisateurs peuvent parcourir l'intégralité de votre site lorsqu'ils ne sont pas connectés.
  2. Vitesse : les ressources proviennent directement du disque et ne nécessitent aucune connexion au réseau.
  3. Résilience : si votre site est interrompu pour cause de "maintenance" (par exemple, si quelqu'un casse tout par inadvertance), vos utilisateurs bénéficieront de l'expérience hors connexion.

Application Cache (ou AppCache) permet à un développeur de spécifier les fichiers que le navigateur doit mettre en cache et mettre à la disposition des utilisateurs hors connexion. Votre application se chargera et fonctionnera correctement, même si l'utilisateur appuie sur le bouton d'actualisation alors qu'il est hors connexion.

Le 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 du fichier manifeste dans la balise html du document:

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

L'attribut manifest doit être inclus sur chaque page de l'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 si elle est explicitement répertoriée dans le fichier manifeste lui-même). Cela signifie que toute page à laquelle l'utilisateur accède et qui inclut un élément manifest est implicitement ajoutée au cache de l'application. Il n'est donc pas nécessaire de lister toutes les pages de votre fichier manifeste. Si une page renvoie vers un fichier manifeste, il n'existe aucun moyen d'empêcher sa mise en cache.

Vous pouvez voir les URL contrôlées par le cache de l'application en accédant à about://appcache-internals/ dans Chrome. Vous pouvez alors vider le cache et afficher les entrées. Des outils pour les développeurs similaires sont disponibles dans Firefox.

L'attribut manifest peut pointer vers une URL absolue ou un chemin d'accès 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 de fichier, mais il 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 à une configuration .htaccess.

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

AddType text/cache-manifest .appcache

Ou, dans 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 par les dernières versions de Chrome, Safari et Firefox, mais vous aurez besoin du type MIME pour fonctionner dans les navigateurs plus anciens et dans IE11.

Structure d'un fichier manifeste

Le fichier manifeste est un fichier distinct vers lequel vous créez un lien via l'attribut "manifest" de 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

Dans cet exemple, quatre fichiers sont mis en cache sur la page qui spécifie ce fichier manifeste.

Voici quelques points à noter:

  • La chaîne CACHE MANIFEST est la première ligne. Elle est obligatoire.
  • Les fichiers peuvent provenir d'un autre domaine
  • Certains navigateurs imposent des restrictions concernant 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 supprime cette restriction.
  • Si le fichier manifeste renvoie un code d'état 404 ou 410, le cache est supprimé.
  • Si le téléchargement du fichier manifeste ou d'une ressource spécifiée échoue, l'ensemble du processus de mise à jour du cache échoue. Le navigateur continuera d'utiliser l'ancien cache d'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 commençant par le signe "#" sont des lignes de commentaire, mais elles peuvent également avoir une autre fonction. Le cache d'une application n'est mis à jour que lorsque son fichier manifeste est modifié. Par exemple, si vous modifiez une ressource image ou une fonction JavaScript, ces modifications ne seront pas mises en cache de nouveau. 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 qui se met à jour en continu 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émarrage et une fois après la mise à jour de tous les fichiers mis en cache. Si le fichier manifeste a changé au cours de la mise à jour, il est possible que le navigateur ait récupéré des fichiers d'une version et d'autres d'une autre version. Dans ce cas, il n'applique pas le cache et effectue une nouvelle tentative ultérieurement.

Le cache est mis à jour, mais le navigateur n'utilise pas ces fichiers tant que la page n'est pas actualisée, car 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) sont 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 tout simplement "", qui autorise toutes les URL. La plupart des sites ont besoin de "". FALLBACK:
Section facultative spécifiant les pages de remplacement si une ressource est inaccessible. Le premier URI correspond à la ressource, 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 défaillances d'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 situées 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 en cache jusqu'à ce que l'une des situations suivantes se produise:

  1. L'utilisateur efface l'espace de stockage du 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 en cache cette ressource. Le fichier manifeste doit être modifié.

État du cache

L'objet window.applicationCache correspond à votre accès programmatique au cache des applications du navigateur. Sa propriété status est utile pour 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 opération tentera de mettre à jour le cache de l'utilisateur (ce qui nécessite que le fichier manifeste ait été modifié). Enfin, lorsque applicationCache.status est à l'état UPDATEREADY, appeler 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 cette opération. Pour mettre à jour les utilisateurs vers la dernière version de votre site, définissez 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 pour des éléments 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);

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

Références