SmarMaker - Documentation
Docs» 03_front:pwa

PWA (Progressive Web App)

Documentation Vite-PWA

Une Progressive Web App (PWA) est une application qui combine le meilleur du web et du mobile. Elle s'installe sur l'écran d'accueil, fonctionne hors connexion et offre une expérience fluide proche d'une app native.

Configuration Vite

Configuration complète

// vite.config.js
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import tailwindcss from "@tailwindcss/vite";
import { VitePWA } from "vite-plugin-pwa";
import path from "path";

export default defineConfig(({ mode }) => {
  const isDev = mode === 'development';

  return {
    appType: 'spa',
    build: isDev ? {
      minify: false,
      sourcemap: true,
    } : {
      minify: 'terser',
      terserOptions: {
        compress: { drop_console: true, drop_debugger: true },
      },
      sourcemap: false,
    },
    optimizeDeps: {
      include: ['prop-types', 'parse-numeric-range', 'boolbase', 'style-to-object', 'debug', 'extend', 'react-signature-canvas'],
    },
    resolve: {
      alias: {
        'src': path.resolve(__dirname, './src'),
        'prop-types': 'prop-types/prop-types.js',
      },
    },
    plugins: [
      react(),
      tailwindcss(),
      VitePWA({
        registerType: 'autoUpdate',
        workbox: {
          globPatterns: ['**/*.{js,css,html,ico,png,svg,json}'],
          cleanupOutdatedCaches: true,
          maximumFileSizeToCacheInBytes: 3000000,
          skipWaiting: true,
          clientsClaim: true,
          runtimeCaching: [
            {
              urlPattern: /\/api\/(home|profile)/,
              handler: 'NetworkFirst',
              options: {
                cacheName: 'api-cache',
                expiration: {
                  maxEntries: 50,
                  maxAgeSeconds: 60 * 60 * 24 * 7,
                },
                cacheableResponse: { statuses: [0, 200] },
                networkTimeoutSeconds: 10,
              },
            },
            {
              urlPattern: /\.(?:png|jpg|jpeg|svg|gif|webp)$/,
              handler: 'CacheFirst',
              options: {
                cacheName: 'images-cache',
                expiration: {
                  maxEntries: 100,
                  maxAgeSeconds: 60 * 60 * 24 * 30,
                },
              },
            },
          ],
        },
        injectRegister: "auto",
        includeAssets: ["favicon.ico", "assets/*", "favicon.png", "apple-touch-icon.png"],
        // Dynamic manifest served by SmartAuth PwaController
        manifest: false,
      }),
    ]
  };
});

Points clés de la configuration

  • Build conditionnel : sourcemaps et logs en dev, minification et suppression des console.log en production
  • Runtime caching : les routes API /api/home et /api/profile sont cachées en NetworkFirst, les images en CacheFirst
  • manifest: false : le manifest n'est pas généré par Vite, il est servi dynamiquement par SmartAuth (voir ci-dessous)

Manifest dynamique (SmartAuth)

SmartBoot utilise un manifest dynamique servi par SmartAuth via le PwaController. Le manifest est généré à partir des constantes Dolibarr de votre module.

Configuration dans index.html

<!doctype html>
<html>
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="manifest" href="api.php/manifest">
    <link rel="icon" type="image/png" href="api.php/icon/64">
    <link rel="apple-touch-icon" href="api.php/icon/192">
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="/src/main.jsx"></script>
  </body>
</html>

Routes SmartAuth

Route Description
GET /manifest Retourne le manifest.json dynamique
GET /icon/{size} Retourne l'icône PWA à la taille demandée (64, 192, 512)

Constantes Dolibarr

Configurez le manifest via les constantes de votre module dans l'administration Dolibarr :

Constante Description Défaut
{MODULE}PWANAME Nom complet de l'application Nom du module
{MODULE}PWASHORTNAME | Nom court (sous l'icône) | Nom du module | | {MODULE}PWADESCRIPTION | Description | - | | {MODULE}PWATHEMECOLOR Couleur du thème #5fbabf
{MODULE}PWABACKGROUND_COLOR Couleur de fond #ffffff

Icônes

Le PwaController cherche les icônes dans cet ordre :

  • Upload personnalisé dans l'administration du module
  • Icône par défaut du module
  • Placeholder généré par GD (si disponible)

Les tailles disponibles sont 64×64, 192×192 et 512×512.

Service Worker et Cache

Stratégies de cache Workbox

La configuration des stratégies de cache se fait dans la section runtimeCaching de la config Vite (voir ci-dessus).

Stratégies disponibles

Stratégie Usage
CacheFirst Assets statiques (fonts, images)
NetworkFirst API, données dynamiques
StaleWhileRevalidate Contenu qui peut être légèrement obsolète
NetworkOnly Toujours réseau (authentification)
CacheOnly Uniquement cache (assets embarqués)

Mise à jour de l'application

SmartCommon fournit le hook usePWAUpdate et le composant UpdatePrompt pour gérer les mises à jour du Service Worker.

usePWAUpdate

Hook pour détecter et appliquer les mises à jour PWA.

import { usePWAUpdate } from '@cap-rel/smartcommon';

const MyApp = () => {
  const {
    updateAvailable,    // true quand une mise à jour est prête
    updateActivated,    // true quand la mise à jour est activée
    checkForUpdates,    // vérification manuelle
    applyUpdate,        // appliquer la mise à jour (skip waiting + reload)
    reloadPage,         // recharger la page
  } = usePWAUpdate({
    autoReload: false,           // recharger automatiquement (défaut: false)
    checkInterval: 0,            // intervalle de vérification en ms (0 = désactivé)
    onUpdateAvailable: () => {}, // callback quand une MAJ est disponible
    onUpdateActivated: () => {}, // callback quand la MAJ est activée
  });

  return (
    <div>
      {updateAvailable && (
        <button onClick={applyUpdate}>
          Mettre à jour
        </button>
      )}
    </div>
  );
};

UpdatePrompt

Composant prêt à l'emploi qui affiche une notification de mise à jour. Trois variantes disponibles :

Variante Description
toast Notification toast en bas de l'écran (défaut)
banner Bandeau fixe en haut ou en bas
modal Fenêtre modale centrée
import { UpdatePrompt } from '@cap-rel/smartcommon';

const App = () => (
  <Provider config={appConfig}>
    <UpdatePrompt
      variant="toast"
      checkInterval={60000}
      labels={{
        title: "Mise à jour disponible",
        message: "Une nouvelle version est disponible.",
        reloadButton: "Rafraîchir",
        dismissButton: "Plus tard",
      }}
    />
    <Router />
  </Provider>
);

Mode Offline

Détecter la connexion

SmartCommon fournit le hook useOnlineStatus qui détecte l'état de la connexion avec support optionnel de health check serveur :

import { useOnlineStatus } from '@cap-rel/smartcommon';

const MyComponent = () => {
  const {
    isOnline,           // true si le navigateur est en ligne
    isServerReachable,  // true/false/null selon le health check
    lastOnline,         // timestamp de la dernière connexion
    checkNow,           // vérification manuelle
  } = useOnlineStatus({
    healthCheckUrl: '/api/health',    // URL de health check (optionnel)
    healthCheckInterval: 30000,       // intervalle en ms (défaut: 30000)
    stabilityDelay: 2000,             // délai de stabilisation (défaut: 2000)
    timeout: 5000,                    // timeout du health check (défaut: 5000)
  });

  return (
    <div>
      {!isOnline && (
        <div className="bg-yellow-500 text-white p-2 text-center">
          Mode hors connexion
        </div>
      )}
    </div>
  );
};

Synchronisation offline

SmartCommon fournit useSyncClient pour la synchronisation offline complète avec gestion de conflits :

import { useSyncClient } from '@cap-rel/smartcommon';

const sync = useSyncClient({
  apiUrl: import.meta.env.VITE_API_URL,
  getAccessToken: () => api.user?.accessToken,
  scope: ['items'],
  autoSync: true,
  syncInterval: 60000,
});

// CRUD offline (les opérations sont mises en file d'attente)
await sync.create('items', { label: 'Nouveau' });
await sync.update('items', id, { label: 'Modifié' });
await sync.remove('items', id);

// Synchroniser manuellement
await sync.sync(); // push + pull

// Vérifier l'état
console.log(sync.pendingCount);  // opérations en attente
console.log(sync.isSyncing);     // synchronisation en cours

Voir Synchronisation offline pour plus de détails.

<note tip>Pour un stockage IndexedDB simple sans synchronisation serveur, vous pouvez aussi utiliser useDb (voir Stockage de données).</note>

Build et déploiement

Commandes

# Build de production
npm run build

# Prévisualiser le build
npm run preview

# Le build génère:
# - dist/index.html
# - dist/assets/*.js
# - dist/assets/*.css
# - dist/sw.js (Service Worker)

Vérification

Après le build, vérifiez dans les DevTools :

  • Application > Manifest : Le manifest est chargé
  • Application > Service Workers : Le SW est actif
  • Application > Storage > Cache Storage : Les assets sont cachés

Déployer sur Dolibarr

Copiez le contenu de dist/ dans le dossier pwa/ de votre module Dolibarr :

# Depuis le dossier mobile/
npm run build
cp -r dist/* ../pwa/

Ou utilisez le Makefile fourni par SmartBoot :

make pwa

Tester la PWA

Lighthouse

  1. Ouvrez les DevTools (F12)
  2. Allez dans l'onglet “Lighthouse”
  3. Sélectionnez “Progressive Web App”
  4. Lancez l'audit

Critères de validation

  • HTTPS (ou localhost en dev)
  • Manifest valide avec icônes
  • Service Worker enregistré
  • Fonctionne hors connexion
  • Responsive design

Voir aussi

  • Configuration - Configuration Vite complète
  • Stockage de données - IndexedDB pour le offline
  • Vite-PWA - Documentation officielle
Previous Next

Made with ❤ by CAP-REL · SmartMaker · GNU AGPL v3+
Code source · Faire un don
SmarMaker - Documentation
Traductions de cette page:
  • Français
  • Deutsch
  • English
  • Español
  • Italiano
  • Nederlands

Table of Contents

Table des matières

  • PWA (Progressive Web App)
    • Configuration Vite
      • Configuration complète
      • Points clés de la configuration
    • Manifest dynamique (SmartAuth)
      • Configuration dans index.html
      • Routes SmartAuth
      • Constantes Dolibarr
      • Icônes
    • Service Worker et Cache
      • Stratégies de cache Workbox
      • Stratégies disponibles
    • Mise à jour de l'application
      • usePWAUpdate
      • UpdatePrompt
    • Mode Offline
      • Détecter la connexion
      • Synchronisation offline
    • Build et déploiement
      • Commandes
      • Vérification
      • Déployer sur Dolibarr
    • Tester la PWA
      • Lighthouse
      • Critères de validation
    • Voir aussi
  • SmartAuth
  • SmartMaker - Back (PHP)
    • Mapping Dolibarr - React
  • SmartMaker - Front (React)
    • Animations de pages
    • Architecture
    • Astuces
    • Calendar
    • Composants et pages
    • Configuration du Provider
    • Debug et Logs
    • Hooks SmartCommon
    • PWA (Progressive Web App)
    • Requêtes API
    • Routage
    • SmartCommon
    • Stockage de données
    • Synchronisation offline
    • Thèmes
    • Traductions
  • HowTo - Pas à pas - Votre première application
    • Développement PHP (back)
    • Développement React (front)
    • Première étape : Module Builder Dolibarr
    • SmartAuth
    • SmartBoot : Un squelette prêt à l'emploi
  • Formation SmartMaker
    • Module 1 : Fondamentaux JavaScript ES6+
      • Chapitre 1 : Variables et Scope
      • Chapitre 2 : Fonctions
      • Chapitre 3 : Programmation Asynchrone
      • Chapitre 4 : Modules ES6
    • Module 2 : Introduction à React
      • Chapitre 1 : Philosophie React
      • Chapitre 2 : JSX
      • Chapitre 3 : Composants
    • Module 3 : Hooks React Fondamentaux
      • Chapitre 1 : useState
      • Chapitre 2 : useEffect
      • Chapitre 3 : useRef
      • Chapitre 4 : useContext
    • Module 4 : React Avancé
      • Chapitre 1 : useCallback et useMemo
      • Chapitre 2 : Custom Hooks
      • Chapitre 3 : Redux et Redux Toolkit
    • Module 5 : Architecture SmartMaker
      • Chapitre 1 : Structure du projet
      • Chapitre 2 : Configuration
      • Chapitre 3 : Flux de données
    • Module 6 : SmartCommon - Composants
      • Chapitre 1 : Mise en page
      • Chapitre 2 : Navigation
      • Chapitre 3 : Formulaires
      • Chapitre 4 : Affichage
    • Module 7 : SmartCommon - Hooks
      • Chapitre 1 : useApi
      • Chapitre 2 : Gestion d'état
      • Chapitre 3 : Hooks utilitaires
      • Chapitre 4 : Synchronisation Offline
    • Module 8 : Backend API (PHP)
      • Chapitre 1 : Routage
      • Chapitre 2 : Controllers
      • Chapitre 3 : Mappers
      • Extrafields et formulaires dynamiques
    • Module 9 : Intégration complète
      • Chapitre 1 : Backend
      • Chapitre 2 : Frontend
      • Chapitre 3 : Déploiement
    • Module 10 : Fonctionnalités avancées
      • Chapitre 1 : Mode offline
      • Chapitre 2 : Internationalisation (i18n)
      • Chapitre 3 : Autres fonctionnalités
    • Module 11 : Bonnes pratiques
  • Démonstration
  • Start
  • Composants et pages
  • Afficher le texte source
  • Anciennes révisions
  • Liens de retour
  • Haut de page