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({
// Réduire les logs en dev
logLevel: 'warn',
// Optimiser les dépendances
optimizeDeps: {
include: [
'prop-types',
'react-signature-canvas',
// Autres dépendances si nécessaire
],
},
// Alias pour les imports
resolve: {
alias: {
'src': path.resolve(__dirname, './src'),
'lib': path.resolve(__dirname, './src/lib'),
},
},
// Plugins
plugins: [
react(),
tailwindcss(),
VitePWA({
// Mise à jour automatique du Service Worker
registerType: 'autoUpdate',
// Configuration Workbox (cache)
workbox: {
// Fichiers à mettre en cache
globPatterns: ['**/*.{js,css,html,ico,png,svg,woff,woff2}'],
// Nettoyer les anciens caches
cleanupOutdatedCaches: true,
// Activer immédiatement le nouveau SW
skipWaiting: true,
},
// Injection automatique du SW
injectRegister: "auto",
// Assets à inclure
includeAssets: [
"favicon.ico",
"favicon.png",
"apple-touch-icon.png",
"assets/*"
],
// Manifest de l'application
manifest: {
name: "Mon Application SmartMaker",
short_name: "MonApp",
description: "Description de mon application",
start_url: "/",
display: "standalone",
background_color: "#ffffff",
theme_color: "#5fbabf",
icons: [
{
src: 'images/pwa-64x64.png',
sizes: '64x64',
type: 'image/png'
},
{
src: 'images/pwa-192x192.png',
sizes: '192x192',
type: 'image/png'
},
{
src: 'images/pwa-512x512.png',
sizes: '512x512',
type: 'image/png',
purpose: 'any'
},
{
src: 'images/maskable-icon-512x512.png',
sizes: '512x512',
type: 'image/png',
purpose: 'maskable'
}
],
},
}),
]
});
Structure des fichiers
public/
favicon.ico
favicon.png
apple-touch-icon.png
images/
pwa-64x64.png
pwa-192x192.png
pwa-512x512.png
maskable-icon-512x512.png
<note important>Les images doivent être dans le dossier public/ et les chemins dans le manifest sont relatifs à ce dossier.</note>
Icônes PWA
Tailles requises
| Taille | Usage |
|---|---|
| 64×64 | Favicon |
| 192×192 | Icône Android/Chrome |
| 512×512 | Splash screen, installation |
| 180×180 | Apple Touch Icon (iOS) |
Icône maskable
L'icône maskable est adaptée aux différentes formes d'icônes (ronde, carrée, etc.) sur Android. La zone de sécurité est un cercle de 80% centré.
Outils pour générer les icônes :
Manifest
Options principales
| Option | Description |
|---|---|
name | Nom complet de l'application |
shortname | URL de démarrage (généralement /) |
display | Mode d'affichage (voir ci-dessous) |
backgroundcolor | Couleur de la barre d'état |
icons | Tableau des icônes |
Modes d'affichage
| Mode | Description |
|---|---|
standalone | Comme une app native (recommandé) |
fullscreen | Plein écran (jeux) |
minimal-ui | Avec contrôles de navigation minimaux |
browser | Dans le navigateur normal |
Service Worker et Cache
Stratégies de cache Workbox
workbox: {
// Cache-first pour les assets statiques
runtimeCaching: [
{
urlPattern: /^https:\/\/fonts\.googleapis\.com\/.*/i,
handler: 'CacheFirst',
options: {
cacheName: 'google-fonts-cache',
expiration: {
maxEntries: 10,
maxAgeSeconds: 60 * 60 * 24 * 365 // 1 an
},
cacheableResponse: {
statuses: [0, 200]
}
}
},
{
// Network-first pour l'API
urlPattern: /^https:\/\/api\.example\.com\/.*/i,
handler: 'NetworkFirst',
options: {
cacheName: 'api-cache',
expiration: {
maxEntries: 100,
maxAgeSeconds: 60 * 60 // 1 heure
},
networkTimeoutSeconds: 10
}
}
]
}
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) |
Mode Offline
Détecter la connexion
import { useEffect, useState } from 'react';
export const useOnlineStatus = () => {
const [isOnline, setIsOnline] = useState(navigator.onLine);
useEffect(() => {
const handleOnline = () => setIsOnline(true);
const handleOffline = () => setIsOnline(false);
window.addEventListener('online', handleOnline);
window.addEventListener('offline', handleOffline);
return () => {
window.removeEventListener('online', handleOnline);
window.removeEventListener('offline', handleOffline);
};
}, []);
return isOnline;
};
Afficher un indicateur offline
import { useOnlineStatus } from './hooks/useOnlineStatus';
const App = () => {
const isOnline = useOnlineStatus();
return (
<div>
{!isOnline && (
<div className="bg-yellow-500 text-white p-2 text-center">
Mode hors connexion
</div>
)}
{/* ... */}
</div>
);
};
Synchronisation avec useDb
Utilisez useDb pour stocker les données localement et synchroniser quand la connexion revient :
import { useDb } from '@cap-rel/smartcommon';
const db = useDb({
name: 'myApp',
stores: {
pendingSync: 'id++, action, data, createdAt'
}
});
// Stocker une action en attente
const saveOffline = async (action, data) => {
await db.pendingSync.add({
action,
data,
createdAt: Date.now()
});
};
// Synchroniser quand en ligne
const syncPending = async (api) => {
const pending = await db.pendingSync.toArray();
for (const item of pending) {
try {
await api.private.post(item.action, { json: item.data });
await db.pendingSync.delete(item.id);
} catch (error) {
console.error('Sync failed:', error);
}
}
};
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) # - dist/manifest.webmanifest
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
- Ouvrez les DevTools (F12)
- Allez dans l'onglet “Lighthouse”
- Sélectionnez “Progressive Web App”
- 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