Construire un tableau blanc collaboratif temps réel avec Svelte et WebSockets
Lorsque l'on pense aux outils collaboratifs modernes, des noms comme Miro ou FigJam viennent immédiatement à l'esprit. Derrière leur fluidité apparente se cachent des défis techniques redoutables : synchronisation des états, gestion des conflits, et latence quasi nulle. Mais doit-on forcément réinventer la roue avec des protocoles exotiques ou des bases de données temps réel ? Pas nécessairement. Avec Svelte et des WebSockets bien maîtrisés, il est possible de construire un tableau blanc collaboratif performant, sans sacrifier la simplicité.
Cet article vous guide pas à pas dans la réalisation d'une telle application, en m'appuyant sur l'expérience de projets similaires et sur les retours de la communauté. Nous aborderons l'architecture, la synchronisation, la gestion des utilisateurs, et les optimisations qui font la différence.
Le socle : Svelte et WebSockets, un duo gagnant
Svelte se distingue par sa réactivité native : les variables réactives mettent à jour le DOM sans overhead. Couplé à WebSockets, qui permet une communication bidirectionnelle persistante, on obtient une base idéale pour le temps réel.
Dans notre cas, chaque action de dessin (tracé, effacement, déplacement d'élément) est envoyée via WebSocket à un serveur Node.js, qui la diffuse aux autres clients. L'état global est maintenu côté serveur, mais chaque client possède une copie locale pour garantir une réponse instantanée.
Architecture : le serveur comme chef d'orchestre
Le serveur joue un rôle central : il reçoit les événements, les valide, et les redistribue. Pour éviter les conflits, chaque événement est horodaté et identifié par un ID unique. En cas de concurrence sur une même forme, c'est le dernier événement reçu qui prime – une approche "last-write-wins" simple mais efficace pour un tableau blanc.
La gestion des sessions est essentielle : chaque tableau blanc possède un identifiant unique. Les clients se connectent à une room spécifique, et le serveur ne transmet les événements qu'aux membres de cette room. Cela limite la charge et garantit la confidentialité.
Gestion des états : le juste équilibre entre local et distant
Un piège classique est de tout synchroniser en temps réel, y compris les états transitoires comme le survol d'une forme. Mieux vaut distinguer:
- Événements permanents : tracés, déplacements, modifications de propriétés – envoyés au serveur et persistés.
- Événements fugaces : curseurs des autres utilisateurs, sélections temporaires – diffusés localement via WebSocket mais non persistés.
Cette distinction réduit la charge serveur et évite une base de données encombrée d'informations inutiles.
Expérience utilisateur : le curseur des autres, fenêtre sur le collaboratif
Voir le curseur d'un collaborateur en temps réel crée un sentiment de présence. Les données de position sont envoyées à haute fréquence (toutes les 50 ms) mais sans garantie de livraison. Pour éviter la saturation, on utilise un throttling côté client.
Attention : le défilement ou le zoom du tableau blanc doit être pris en compte. Chaque événement de souris est converti en coordonnées logiques (par rapport au canvas), et non en pixels écran, pour que tous les utilisateurs voient le curseur au bon endroit.
Gestion des conflits : l'und/redo en mode multijoueur
L'undo/redo est un casse-tête en environnement collaboratif. La solution retenue : chaque utilisateur possède sa propre pile d'undo locale, mais les actions undo sont converties en événements "inverses" qui sont envoyés au serveur. Ainsi, annuler un trait revient à envoyer un événement "supprimer ce trait" à tous. Cette approche, bien que plus complexe, évite les incohérences.
Pour approfondir, Liveblocks propose une excellente analyse des stratégies d'undo/redo en multijoueur, qui a inspiré notre implémentation.
Performances et scalabilité
Pour un usage modéré (moins de 100 utilisateurs simultanés sur un même tableau), un serveur Node.js unique suffit. Au-delà, il faut envisager une architecture distribuée avec Redis pour le partage d'état entre instances. NATS, mentionné dans des projets similaires, peut également servir de backbone de messagerie.
Côté client, le canvas HTML5 est préféré au SVG pour les performances de rendu. Les formes sont redessinées à chaque frame, mais seules les zones modifiées sont mises à jour grâce à des dirty rectangles.
Déploiement et considérations pratiques
Le serveur WebSocket peut être déployé sur une plateforme comme Heroku ou Fly.io. Attention aux connexions longues : les timeouts des load balancers doivent être configurés pour ne pas couper les WebSockets. L'utilisation de SSL est indispensable pour les environnements de production.
Côté stockage, une base de données simple comme SQLite ou PostgreSQL peut enregistrer l'état final du tableau (liste des formes avec leurs propriétés). Pour des besoins temps réel plus poussés, Supabase Realtime offre une solution clé en main.
Retour d'expérience : leçons apprises
Lors de la construction d'un prototype, plusieurs pièges ont été identifiés :
- Ne pas négliger la compression : les messages WebSocket peuvent être compressés avec permessage-deflate pour réduire la bande passante.
- Gérer la reconnexion : après une perte de connexion, le client doit demander l'état complet du tableau pour se resynchroniser.
- Tester avec des vrais utilisateurs : les tests unitaires ne remplacent pas des sessions réelles avec des dizaines de personnes dessinant en même temps.
Conclusion
Construire un tableau blanc collaboratif avec Svelte et WebSockets est un projet à la fois accessible et formateur. En respectant une architecture simple mais robuste, en gérant correctement les états et les conflits, on obtient une application fluide et agréable. Les outils modernes comme Svelte simplifient la réactivité, tandis que WebSockets assurent la communication en temps réel.
Alors, prêt à vous lancer ? Ouvrez votre éditeur, installez quelques dépendances, et commencez par un simple échange de coordonnées de souris. Le reste viendra par itération.
Pour aller plus loin
- Medium - Building a Real-Time Collaborative Whiteboard Backend with NestJS and Socket.IO - Un article détaillant une approche similaire avec NestJS.
- Supabase Realtime Docs - Documentation sur les capacités temps réel de Supabase, utiles pour le stockage et la synchronisation.
- Reddit - How to start learning WebSockets - Discussion avec des conseils pratiques pour débuter.
- Reddit - Reactive, optimistic-by-default WebSocket library - Présentation d'une bibliothèque WebSocket réactive pour les apps collaboratives.
- Hacker News - Matrix-CRDT: real-time collaborative apps using Matrix - Une approche alternative basée sur Matrix et les CRDT.
- Hacker News - How to build undo/redo in a multiplayer environment by Liveblocks - Analyse des stratégies d'undo/redo en environnement multijoueur.
- Reddit - itty-sockets: dead-simple realtime messaging in Svelte - Une bibliothèque légère pour le temps réel avec Svelte.
