Offline-first : une PWA qui continue de fonctionner sans réseau
Quand la connexion est instable, une application qui affiche un écran blanc perd la confiance de ses utilisateurs. Voici l'architecture qui garde Faciloop utilisable hors ligne.
Les équipes commerciales qui utilisent Faciloop travaillent souvent sur le terrain, avec une connexion mobile qui va et vient. Une application qui bloque à chaque coupure n'est pas utilisable. L'objectif : que l'interface reste rapide et fonctionnelle, que le réseau soit là ou non.
Trois couches qui travaillent ensemble
- Workbox met en cache l'application elle-même (HTML, JS, CSS, polices) : elle s'ouvre même sans réseau.
- Dexie.js garde une copie locale des données dans IndexedDB : listes et fiches s'affichent instantanément.
- TanStack Query synchronise cette copie avec le serveur quand la connexion le permet.
Lire d'abord en local
L'interface lit toujours la base locale. Le réseau sert à la rafraîchir en arrière-plan, pas à afficher la page. Résultat : pas d'écran de chargement à chaque navigation, et une application qui reste consultable en mode avion.
import Dexie, { type Table } from "dexie";
export class LocalDB extends Dexie {
prospects!: Table<Prospect, string>;
outbox!: Table<PendingChange, number>;
constructor() {
super("faciloop");
this.version(1).stores({
prospects: "id, organization_id, updated_at",
outbox: "++seq, created_at",
});
}
}
export const db = new LocalDB();Écrire hors ligne : une file d'attente
Une modification faite hors ligne est appliquée tout de suite en local, puis enregistrée dans une table outbox. Au retour du réseau, la file est rejouée dans l'ordre vers le serveur. Si une requête échoue, elle reste dans la file et l'utilisateur ne perd rien.
export async function flushOutbox() {
const pending = await db.outbox.orderBy("seq").toArray();
for (const change of pending) {
await sendToServer(change); // throws if offline: we retry later
await db.outbox.delete(change.seq!);
}
}
window.addEventListener("online", () => void flushOutbox());Ce que j'ai appris
- Afficher clairement l'état (en ligne, hors ligne, synchronisation en cours) rassure plus que n'importe quelle animation.
- Décider tôt qui gagne en cas de conflit : ici, le serveur reste la source de vérité.
- Tester en conditions réelles : le mode avion du téléphone révèle plus de bugs que l'onglet réseau du navigateur.