Publié par
Il y a 8 années · 10 minutes · Front

Application hors-ligne avec HTML5 – le manifest

Dans le train, l’avion, plus généralement en déplacement, combien se retrouvent perdus sans la précieuse connexion à internet ? Rappelez vous la dernière fois que vous avez voulu consulter un article ou une documentation en ligne. Prenons le cas d’un blog : vous voulez pouvoir le lire en déplacement, voire même pouvoir éditer vos articles en cours de rédaction. Avec le manifest de cache HTML5, il est possible de rendre disponible hors-ligne les interfaces web. Dans cet article, nous étudierons la mise en pratique d’un manifest de cache appliquée à un blog.

Sommaire

Principe de fonctionnement

Une page HTML intègre une référence vers un fichier manifest. Celui-ci liste les URL des ressources à mettre dans le cache. Quand le navigateur charge la page pour la première fois, il va télécharger toutes les URL du manifest et les stocke dans le cache. Tous les chargements suivants se feront directement à partir du cache sans passer par le serveur.

En parallèle, le navigateur va vérifier la version de son fichier manifest auprès du serveur. En cas de mise à jour, le navigateur va télécharger l’intégralité des ressources dans un nouveau cache, qui sera utilisé pour tous les chargements suivants.

Que le navigateur soit en ligne ou hors-ligne, il n’y a plus aucun impact sur l’affichage de la page qui vient directement du cache.
Maintenant que vous connaissez le principe de fonctionnement passons à la première étape.

Écrire le manifest du cache

Il s’agit d’un fichier texte encodé en UTF-8 qui contient une liste d’URLs réparties en trois sections :

  • CACHE : C’est la section par défaut, elle contient les URLs que le navigateur doit impérativement mettre en cache.
  • NETWORK : Liste les URLs qui doivent toujours être consultées sur le serveur. Ce sera par exemple le cas des ressources AJAX et des ressources externes (publicité, …).
  • FALLBACK : Cette section permet d’associer des préfixes d’URL à des ressources alternatives utilisées en cas d’indisponibilité.

Passons maintenant à la pratique : la première chose à faire est de créer notre cache manifest.

CACHE MANIFEST
# Version 1 25/09/2010
images/img01.gif
images/img02.gif
images/img03.gif
styles/default.css
lib/demo.js
demo.html
offline.html

NETWORK:
/online.html

FALLBACK:
/online  offline.html

Le navigateur doit donc conserver en cache les ressources statiques du site (images, css, javascript), ainsi que la page demo.html.
La page online.html sera toujours consultée sur le serveur. En cas d’indisponibilité, le navigateur affichera la page offline.html à la place du service en ligne.

Par défaut, seules les ressources listées dans le cache explicite sont disponibles. Par exemple : si vous oubliez de lister une image, celle-ci ne sera pas affichée dans la page. Il faut donc lister toutes les ressources, ou bien ajouter le joker ‘*’ dans la section NETWORK afin de permettre le téléchargement des ressources manquantes. Les ressources listées dans la section CACHE sont toujours prioritaires sur les autres. De ce fait, le joker n’a aucune incidence sur la mise en cache, il permet seulement d’accéder à d’autres ressources, y compris sur des domaines différents.

Intégrer le manifest à l’application

Pour activer le cache, il reste maintenant à ajouter le fichier dans l’application web et à référencer son URL dans l’attribut manifest='cache-manifest.mf' en s’assurant qu’il est encodé en UTF-8 et que le serveur lui donnera bien le type mime ‘text/cache-manifest’.

web.xml:

<mime-mapping>
    <extension>mf</extension>
    <mime-type>text/cache-manifest</mime-type>
</mime-mapping>

Pages HTML:

<html manifest="cache-manifest.mf">
...

Au premier chargement d’une page, le navigateur va construire son cache en téléchargeant toutes les ressources listées dans le manifest et afficher la page. Après quoi, le navigateur affichera toujours cette page à partir du cache.
Notez bien que toute page référençant le manifest est ajoutée dans le cache explicite associé à ce dernier. Dans le cas de la page online.html, il ne faut donc surtout pas y référencer le fichier manifest.

Nous avons maintenant une première démonstration fonctionnelle que l’on peut qualifier de preuve de concept. Nous souhaitons modifier la page demo.html pour y ajouter un peu de contenu. Malheureusement, vous l’aurez compris, la modification du fichier html sur le serveur n’a aucun effet immédiat.

Gérer la mise à jour du cache

Souvenez vous, le navigateur vérifie toujours la version du fichier manifest au chargement des pages du cache. Si le manifest n’est plus à jour, le navigateur va le récupérer et va télécharger l’ensemble des ressources dans une nouvelle version du cache en tache de fond. Au prochain chargement de la page, le navigateur utilisera le cache le plus à jour et vous pourrez constater la prise en compte de vos modifications.

Attention, les ressources du manifest sont téléchargées en outrepassant les directives de cache HTTP. A contrario, le fichier manifest est géré dans un cache standard du navigateur, ce qui signifie qu’il respecte les standards de mise en cache. Si le serveur est configuré pour forcer la mise en cache pendant trois semaines du fichier manifest, il vous faudra attendre autant de temps avant de pouvoir voir la moindre modification de votre interface.

En développement, l’interface change régulièrement, il donc est impératif d’interdire la mise en cache du fichier à l’aide du header HTTP Cache-Control. Pour la production, les directives de cache peuvent-être plus agressives (24h par exemple) car l’interface évolue moins vite. Les en-têtes HTTP peuvent-être positionnées à l’aide d’un filtre sur l’URL du manifest ou d’une Servlet générant le manifest.

A chaque modification du fichier manifest détectée par le navigateur, celui-ci re-télécharge l’intégralité du cache. Pour garantir la mise à jour du cache à chaque nouvelle version de l’application, il faut donc modifier le fichier manifest. C’est le rôle du commentaire # version 1 25/09/2010 qui changera à chaque livraison ou déploiement de l’application.

Le site est donc consultable hors-ligne et nous sommes capables de forcer la mise à jour du cache. L’utilisateur pourra continuer à consulter le site et verra une page d’erreur appropriée s’il tente d’accéder à des services indisponibles. Pour un site statique c’est très bien mais quand on parle d’application, on pense à quelque chose de dynamique.

Gérer le cache en JavaScript

Pour un blog dont le contenu évolue lentement, il est envisageable de s’assurer que la version du manifest soit changée à chaque nouvel article. Le manifest devient alors un service généré par l’application qui change le commentaire de version à chaque nouvel article.
Malheureusement, l’utilisateur ne pourra voir le nouvel article qu’à son deuxième passage sur le site, une fois que le cache aura été mis à jour. Un début de solution est d’utiliser l’API JavaScript pour recharger automatiquement la page lorsque le nouveau cache est prêt.

L’objet window.applicationCache va nous permettre de :

  • Suivre l’activité et l’état du cache associé au document courant.
  • Lancer le téléchargement de la nouvelle version du cache si le manifest a changé.
  • Activer la nouvelle version du cache pour que les prochains chargements l’utilisent.
<script>

// Activer le nouveau cache quand il est disponible et recharger la page
window.applicationCache.addEventListener('updateready', function (){
  	window.applicationCache.swapCache();
  	alert('mise a jour du cache');
  	window.location.reload();
}, false);

// Notifier les erreurs
window.applicationCache.addEventListener('error', function (evt){
	alert('Erreur du cache : ' + evt);

}, false);

// Vérification de la version du manifest
window.applicationCache.addEventListener('checking', function (evt){
	alert('Vérification du cache : ' + evt);
}, false);

// Télécharger le nouveau cache quand le manifest a changé
window.applicationCache.addEventListener('obsolete', function (evt){
	alert('Le cache est obsolète : ' + evt);
	window.applicationCache.update();
}, false);

// Le manifest n'a pas changé
window.applicationCache.addEventListener('noupdate', function (evt){
	alert('Pas de mise à jour du cache : ' + evt);
}, false);
</script>

Ce code rechargera automatiquement la page du navigateur lorsque le cache aura été mis à jour. Le lecteur du blog peut maintenant voir rapidement le nouvel article ou tout du moins son introduction. Pour pouvoir lire l’article hors-ligne, il faudra qu’il pense à afficher la page au moins une fois pour la mettre en cache.

Aller plus loin avec le manifest

La solution peut être de créer un service générant le manifest en changeant, d’une part, de version à chaque nouvel article publié et, d’autre part, en listant les URLs des derniers articles dans le cache explicite. Le chargement prendra plus de temps mais le lecteur pourra consulter l’article hors-ligne sans plus d’effort.

Attention, les pages implicites qui déclarent le manifest sans être listées dans ce dernier y sont ajoutées et seront téléchargées elles aussi lors de la mise à jour du cache.
Soyez prudent quand vous activez le manifest et ne multipliez pas les pages. Dans le cas du blog par exemple les pages affichant les articles ne doivent pas utiliser le manifest. Le lecteur ne souhaite certainement pas télécharger l’ensemble des articles qu’il a déjà lu à chaque nouvel article.

Cette solution minimaliste peut convenir à certains, mais elle n’est pas applicable pour un site dont le contenu change beaucoup ou pour un site à fort trafic tant l’utilisation du cache est mauvaise.

Pour optimiser l’utilisation du cache, il faut le considérer comme la vue statique de l’application qui évoluera au gré des changements d’interface et non au gré du contenu. Le contenu dynamique devra être servi par des requêtes asynchrones. Pour la mise en cache et le fonctionnement il faudra utiliser les nouvelles API JavaSript : LocalStorage et document.onLine. De cette manière, le manifest redeviendra un fichier statique évoluant au gré des versions de l’application.

Pour garantir l’indexation du contenu par les moteurs de recherche et assurer la compatibilité avec d’anciens navigateurs, prévoyez toujours un mode dégradé sans manifest ni contenu asynchrone.

Notes de sécurité

Notez que le cache est maintenu par nom de domaine. Il n’existe qu’une seule instance du même manifest pour un serveur. Pour les serveurs hébergeant plusieurs applications, l’utilisation d’hôte virtuel est plus que conseillée.

Le cache ne doit jamais contenir de données confidentielles. Les pages de login et tous services de sécurité doivent être exclus du cache. Ne les listez jamais dans le manifest sauf pour les exclure et surtout n’intégrez pas le manifest dans ces pages.

Informez l’utilisateur sur les dangers de ce service et surtout laissez le choisir d’activer ou non le fonctionnement hors ligne. En effet si le navigateur lui-même n’est pas protégé, toute personne y ayant accès pourra consulter le cache. Pour limiter le problème vous pouvez activer le service en stockant un cookie sur le navigateur si l’utilisateur active le mode hors ligne. Ainsi le lecteur devra répéter l’opération pour tous les navigateurs sur lesquels il souhaite consulter le site.

En dehors de ces règles de sécurité basiques, toutes les règles de sécurité inhérentes aux sites web s’appliquent.

Conclusion

Dans ce premier article, nous avons posé la première pierre d’une application hors-ligne, en intégrant un fichier manifest pour mettre en cache son interface et ses ressources statiques. Dans le prochain article, nous verrons comment utiliser les nouvelles API JavaScript pour permettre de lire et d’éditer du contenu hors-ligne.

Les points importants du manifest :

  • Versionnez le manifest avec un commentaire
  • Désactivez ou maitrisez les directives de cache HTTP
  • Minimisez le nombre de pages référençant le manifest
  • Stockez uniquement les ressources statiques du site

4 thoughts on “Application hors-ligne avec HTML5 – le manifest”

  1. Publié par jpvincent, Il y a 8 années

    bonjour

    vous suggérez d’utiliser l’offline comme un super cache même pour un blog, en utilisant JS pour les cas où le contenu a changé mais que l’utilisateur ne peut pas encore le voir et doit attendre le 2nd chargement. J’avais pensé à la même solution, mais elle me semble risquée
    Avez vous testé en production la solution que vous préconisez ?

  2. Publié par Séven Le Mesle, Il y a 8 années

    @jpvincent: A vrai dire, ce n’est pas une pratique que je recommanderai. D’ailleurs je dois avouer que je n’ai pas d’expérience de production en la matière. Si j’ai pris cet exemple, c’est précisément car il permet d’illustrer les inconvénients du manifest. Ma conclusion sur les différents POC que j’ai réalisés est plutôt, de ne pas utiliser le manifest de cette façon. Comme vous pourrez le constater dans le prochain article, à mon sens, la solution la plus satisfaisante réside plutôt dans l’utilisation de requêtes AJAX pour récupérer les articles. En utilisant le cache manifest comme un template du site dont le contenu est fusionné en JavaScript par le navigateur. Maintenant rien n’empêche de tester cette solution en simulant une charge de production avec jmeter par exemple.

  3. Publié par Cédric, Il y a 7 années

    Bonjour,

    Tout d’abord merci pour ce tutoriel. Voilà je fais actuellement mon mémoire sur les applications web offline en général. Je suis à la recherche (désespérée) d’une doc technique, expliquant comment le manifest s’appuie sur les fonctionnalités du cache du navigateur.

    Pouvez vous me renseigner?
    Cdt,
    Cédric

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *