Skip to main content
Une illustration vectorielle plate sur un fond géométrique pastel montre un ordinateur portable et un smartphone, affichant tous deux un site web "HUGO BLOG". L'écran de l'ordinateur portable montre la mise en page bureau complète, tandis que l'écran du smartphone affiche une version optimisée mobile avec un doigt cliquant sur un bouton étiqueté "INSTALL APP". Des icônes pour le mode hors-ligne (nuage barré) et la vitesse (éclair) sont autour des appareils.

Rendez votre site Hugo installable & prêt pour le hors-ligne (Tutoriel PWA)

6 min 1,302 words
Note

Archive Technique

Cet article discute de la version précédente de ce blog, qui était construit avec Hugo. Le site est maintenant propulsé par Astro. Bien que les concepts de sécurité explorés ici restent valides, les détails d’implémentation spécifiques liés à Hugo ne s’appliquent plus au site en ligne.

Dans cet article, j’introduirai le concept de “Progressive Web App” (PWA) et explorerai ses avantages par rapport aux applications web classiques. Ensuite, je détaillerai comment j’ai transformé mon blog Hugo en PWA, soulignant les spécificités de chaque plateforme, pour que vous puissiez appliquer la même transformation à votre propre site web.

Qu’est-ce qu’une PWA ?

Commençons par définir ce qu’est une PWA. C’est une application construite en utilisant les technologies de la plateforme web (typiquement HTML, CSS et JavaScript) qui offre une expérience utilisateur similaire à une application spécifique à une plateforme (pensez à une app native installée depuis le Google Play Store sur Android ou l’App Store sur iOS).

Les Progressive Web Apps possèdent plusieurs fonctionnalités clés :

  • Compatibilité multi-plateforme : Avec une seule base de code, les PWA tournent sur de multiples plateformes (Linux, Android, Windows, macOS, iPadOS) et appareils (ordinateurs de bureau, tablettes, smartphones).

  • Capacité hors-ligne : Grâce à un Service Worker—un composant clé des PWA—les ressources sont stockées dans un cache, permettant à l’app de fonctionner même sans connexion internet.

  • Installabilité : Les navigateurs web détectent automatiquement les capacités PWA et invitent les utilisateurs à installer le site web comme une application native (iOS a des spécificités que je détaillerai plus tard). Les utilisateurs obtiennent une interface “app-like” avec un écran de démarrage (splash screen), des icônes, des gestes et des animations natives.

  • Confiance et sécurité : Les PWA doivent être servies via HTTPS, garantissant la sécurité et l’intégrité des données.

  • Découvrabilité : Puisqu’elle reste un site web, votre application et ses pages peuvent être indexées et atteintes directement via les moteurs de recherche.

  • Mises à jour automatiques : Les PWA bénéficient de la plus grande force du web : elles se mettent à jour automatiquement. Contrairement aux apps natives, les utilisateurs n’ont pas besoin de télécharger manuellement les mises à jour.

  • Indépendance des Store : Les PWA sont installables directement depuis le navigateur, contournant les magasins d’applications.

En bref, pour transformer votre site web en Progressive Web App, vous avez besoin de trois éléments principaux :

  1. Un fichier manifest : Un fichier JSON définissant les métadonnées de l’app (nom, icônes, chemin, etc.).

  2. Un Service Worker : Un script pour gérer le cache et la fonctionnalité hors-ligne.

  3. Des Icônes d’App : Bien que techniquement optionnelles pour un site web, elles sont obligatoires pour une expérience installable soignée.

Vous devez aussi référencer le manifest et le service worker dans votre HTML. De plus, votre site web doit être responsive (s’adaptant aux ordinateurs portables, tablettes et smartphones) et servi via HTTPS.

Le webmanifest.json

Vérifiez les MDN web docs pour une liste complète des propriétés du manifest. Ce fichier est typiquement stocké à la racine du site web.

Créez un fichier nommé webmanifest.json dans votre dossier static. Ci-dessous est le contenu que j’utilise pour mon site web, que vous pouvez utiliser comme modèle :

{
  "lang": "fr",
  "name": "LaRomierre",
  "short_name": "LaRomierre",
  "description": "Le blog LaRomierre",
  "start_url": "/",
  "scope": "/",
  "background_color": "#929295",
  "theme_color": "#F5F5FA",
  "display": "standalone",
  "icons": [
    {
      "src": "/icons/pwa-64x64.png",
      "type": "image/png",
      "sizes": "64x64"
    },
    {
      "src": "/icons/pwa-192x192.png",
      "type": "image/png",
      "sizes": "192x192"
    },
    {
      "src": "/icons/pwa-512x512.png",
      "type": "image/png",
      "sizes": "512x512"
    },
    {
      "src": "/icons/pwa-512x512.png",
      "sizes": "512x512",
      "type": "image/png",
      "purpose": "maskable"
    }
  ],
  "shortcuts": [
    {
      "name": "Decap CMS",
      "description": "CMS pour ajouter ou éditer des articles de blog",
      "url": "/admin/index.html",
      "icons": [
        {
          "src": "/icons/decap/pwa-192x192.png",
          "type": "image/png",
          "sizes": "192x192"
        }
      ]
    },
    {
      "name": "Posts Tech",
      "description": "La page contenant les posts tech",
      "url": "/categories/tech/",
      "icons": [
        {
          "src": "/icons/tech/pwa-192x192.png",
          "type": "image/png",
          "sizes": "192x192"
        }
      ]
    },
    {
      "name": "Posts Management",
      "description": "La page contenant les posts management",
      "url": "/categories/management/",
      "icons": [
        {
          "src": "/icons/mgmt/pwa-192x192.png",
          "type": "image/png",
          "sizes": "192x192"
        }
      ]
    }
  ]
}

Focus sur les Éléments du Manifest

Les Icônes

Les icônes définies dans le manifest servent plusieurs objectifs : identifier l’app installée, générer l’écran de démarrage, apparaître dans la barre des tâches ou le dock, et dans le sélecteur d’applications (ex. cmd+tab sur macOS).

Vous avez probablement remarqué que j’ai défini plusieurs icônes. Cela permet au système de choisir la taille la plus appropriée pour le contexte. Je recommande fortement d’expérimenter avec cela : essayez de créer des icônes monochromes—un carré jaune pour 64x64, un rouge pour 128x128, etc.—pour voir exactement quelle icône est utilisée où.

Sur un smartphone Android, sans icône maskable définie
Sur un smartphone Android, sans icône maskable définie

Sur un smartphone Android, avec une icône maskable définie
Sur un smartphone Android, avec une icône maskable définie

Pour créer ces assets facilement, je recommande maskable.app pour visualiser à quoi ressemble votre icône quand elle est masquée (arrondie/formée par l’OS). J’utilise aussi le assets-generator de vite-pwa, qui peut générer toutes les tailles nécessaires depuis une seule image d’entrée.

Le paramètre purpose est crucial. any (défaut) signifie que l’icône peut être utilisée partout. maskable indique que l’icône est conçue pour être rognée en toute sécurité (ex. dans un cercle sur Android) sans perdre d’information. monochrome est utilisé pour des contextes d’UI spécifiques comme les barres de statut.

Modes d’Affichage (Display Modes)

Le paramètre display contrôle à quel point l’app semble immersive.

  • fullscreen : L’app prend tout l’écran. Les barres système sont cachées.

  • standalone : Ressemble à une app native standard. La barre de statut (batterie, horloge) reste visible, mais les contrôles de navigation du navigateur sont cachés. C’est le choix le plus commun pour les PWA.

  • minimal-ui : Conserve certains contrôles du navigateur (comme la navigation).

  • browser : L’app s’ouvre dans un onglet de navigateur standard. De façon cruciale, ce mode désactive l’invite d’installation.

Écran de Démarrage (Splash Screen)

Sur Android, le système génère un écran de démarrage en utilisant la couleur de fond et l’icône définie dans votre manifest. Android priorise les icônes avec le purpose: "maskable".


Le splash screen sur les appareils Android

Raccourcis (Shortcuts)

La section shortcuts définit des actions rapides accessibles via un appui long sur l’icône de l’app (Android/iOS) ou un clic droit (Desktop). Dans mon manifest, j’ai ajouté des raccourcis vers des catégories de blog spécifiques et mon panneau d’admin CMS.

Référencer le Manifest

Enfin, liez le manifest dans votre section <head> HTML (généralement dans layouts/_default/baseof.html ou layouts/partials/head.html dans Hugo) :

<link rel="manifest" href="/webmanifest.json">

Le Service Worker

Le Service Worker remplit la promesse “hors-ligne”. C’est un fichier JavaScript (ex. service-worker.js) placé à la racine de votre site qui intercepte les requêtes réseau.

Le code ci-dessous implémente une stratégie où :

  1. À l’Installation (On Install) : Il met en cache une page “Offline” spécifique.

  2. Au Fetch (On Fetch) : Il vérifie le cache d’abord. Si une page est en cache et non expirée (2 heures dans cet exemple), il la sert. Sinon, il la récupère depuis le réseau, met à jour le cache, et la sert.

  3. Repli (Fallback) : Si le réseau est indisponible et la page n’est pas en cache, il sert la page /offline/.

const CACHE_NAME = 'laromierre_cache_v1';
const CACHE_DURATION = 7200; // 2 hours

self.addEventListener('install', function (event) {
  event.waitUntil(
    caches.open(CACHE_NAME)
    .then(function (cache) {
      return cache.addAll(['/offline/']);
    })
  );
});

self.addEventListener('fetch', function (event) {
  // Exclude extensions, localhost, and admin sections
  if (event.request.url.startsWith('chrome-extension://') ||
      event.request.url.includes('localhost') ||
      event.request.url.includes('/admin/')) {
    return;
  }

  event.respondWith(
    caches.match(event.request).then(function (response) {
      if (response) {
        const headers = response.headers.get('date');
        if (headers) {
          const expirationDate = new Date(headers).getTime() + CACHE_DURATION * 1000;
          if (new Date().getTime() > expirationDate) {
            return fetchAndUpdateCache(event.request);
          }
        }
        return response;
      }
      return fetchAndUpdateCache(event.request);
    })
  );
});

function fetchAndUpdateCache(request) {
  return fetch(request).then(function (networkResponse) {
    if (networkResponse && networkResponse.status === 200) {
      const clonedResponse = networkResponse.clone();
      caches.open(CACHE_NAME).then(function (cache) {
        cache.put(request, clonedResponse);
      });
    }
    return networkResponse;
  }).catch(function () {
    return caches.match('/offline/');
  });
}

Enregistrer le Service Worker

Ajoutez ce script à votre HTML (typiquement dans le footer ou strictement à l’intérieur du <body>) :

<script>
    if ('serviceWorker' in navigator) {
        window.addEventListener('load', function () {
            navigator.serviceWorker.register('/service-worker.js')
                .then(reg => console.log('SW registered!', reg.scope))
                .catch(err => console.log('SW registration failed:', err));
        });
    }
</script>

Tester avec Lighthouse

Pour vérifier votre PWA, utilisez les Google Chrome DevTools. Clic droit > Inspecter, puis allez dans l’onglet Lighthouse. Assurez-vous que “Progressive Web App” est coché et lancez l’analyse.

Analyse Lighthouse pour blog.laromierre.com

Lighthouse validera votre manifest, service worker, et sécurité (HTTPS), fournissant une checklist de tous les prérequis manquants.

Installation de l’App à Travers les Appareils

Desktop (Chrome & Edge)

Chrome et Edge offrent le meilleur support. Une icône d’installation apparaît dans la barre d’adresse. Une fois installée, l’app s’intègre avec l’OS (Menu Démarrer, Spotlight). Un clic droit sur l’icône du dock montre même les raccourcis définis dans votre manifest !

Firefox

Mozilla a abandonné le support PWA dans Firefox 85 (2021). Vous ne pouvez pas installer de PWA nativement avec Firefox.

iOS (iPhone & iPad)

iOS supporte les PWA mais avec des limitations. Il n’y a pas d’invite “Installer” automatique. Les utilisateurs doivent manuellement taper Partager > Sur l’écran d’accueil.

Bien que le support iOS s’améliore, il nécessite des optimisations spécifiques (comme définir des liens apple-touch-icon dans votre HTML, car iOS ne se repose pas encore entièrement sur le manifest pour les icônes). Je couvrirai les spécificités iOS dans un futur article dédié.

Conclusion

Dans cet article, nous avons couvert les essentiels de la PWA : le Manifest, le Service Worker, et le processus d’installation. En transformant votre blog Hugo en PWA, vous améliorez la performance, permettez la lecture hors-ligne, et augmentez l’engagement utilisateur.

J’espère que cela vous aidera à construire la vôtre !

Références