Back to flin
flin

Rechargement à chaud de modules en 42 ms

Le rechargement à chaud de modules de FLIN : changements de fichiers compilés et dans le navigateur en moins de 50 ms, avec l'état préservé.

Juste A. Gnimavo (Thales) & Claude | March 26, 2026 5 min flin
EN/ FR/ ES
flinhot-reloadhmrdeveloper-experienceperformancewatcher

La boucle de rétroaction la plus rapide gagne. Quand un développeur change une ligne de code, le temps entre la sauvegarde du fichier et le résultat visible dans le navigateur détermine s'il reste dans l'état de flow ou perd le fil de ses pensées. Pour FLIN, nous avons fixé un objectif : moins de 50 millisecondes de la sauvegarde du fichier à la mise à jour du navigateur. Nous avons atteint 42 ms.

La Session 028 a été entièrement dédiée à ce problème. Le résultat était un système complet de rechargement à chaud de modules (HMR) : un observateur de fichiers qui détecte les changements, un pipeline de recompilation incrémentale, un endpoint Server-Sent Events (SSE) qui pousse les mises à jour au navigateur, et un script côté client qui applique ces mises à jour sans rechargement complet de page.

C'est l'histoire de comment nous l'avons construit.


L'architecture

Le système HMR a quatre composants :

Système de fichiers -> Observateur de fichiers -> Compilateur -> Diffuseur SSE -> Navigateur
  1. L'observateur de fichiers surveille le fichier source .flin pour les changements.
  2. Quand un changement est détecté, le compilateur recompile le fichier.
  3. Si la compilation réussit, le diffuseur SSE envoie un événement de rechargement à tous les navigateurs connectés.
  4. Le navigateur reçoit l'événement et recharge la page.

Chaque composant est simple. La complexité est dans les faire fonctionner ensemble rapidement et de manière fiable.


Le décompte temporel

Où vont les 42 millisecondes ?

PhaseTempsDescription
Notification du système de fichiers~5 msL'OS détecte le changement, notifie l'observateur
Recompilation~15 msLexer + parser + vérificateur de types + générateur de code
Diffusion SSE~1 msEnvoi sur le canal + push HTTP
Réception navigateur + rechargement~21 msCallback EventSource + rechargement de page
Total~42 msSauvegarde du fichier à mise à jour visible

Le coût dominant est le rechargement du navigateur (21 ms), pas la compilation (15 ms). C'est parce que le navigateur doit démonter la page courante, demander le nouveau HTML, l'analyser, le mettre en page et le peindre. Même pour une petite page, c'est une quantité non triviale de travail.

La phase de compilation est rapide parce que les fichiers FLIN sont petits (une application typique fait moins de 500 lignes) et le compilateur est une conception en un seul passage. Il n'y a pas de passe d'optimisation, pas de tree-shaking, pas de code splitting. Le compilateur lit le source, produit du bytecode, et la VM rend du HTML. Chaque étape est linéaire dans la taille de l'entrée.


Ce qui rend cela rapide

Trois décisions architecturales contribuent à l'objectif de moins de 50 ms.

Architecture mono-fichier. Il n'y a pas de graphe de modules à invalider. Quand un fichier change, recompiler ce fichier. Point. Des frameworks comme webpack et Vite passent un temps significatif à déterminer quels modules sont affectés par un changement et lesquels peuvent être réutilisés. FLIN saute cela entièrement.

Pas de bundling. Il n'y a pas de bundle JavaScript à régénérer. Le serveur de développement FLIN produit du HTML directement. Le seul JavaScript est le runtime réactif de 50 lignes et le client HMR. Il n'y a pas de tree-shaking, pas de minification, pas de génération de source maps.

Pas d'hydratation. Le serveur produit du HTML complet. Le navigateur le rend. Il n'y a pas d'étape d'hydratation où le JavaScript côté client doit « s'attacher » au balisage rendu côté serveur. Cela élimine une phase qui peut prendre 100-500 ms dans des frameworks comme Next.js ou Nuxt.


Comparaison avec les systèmes HMR existants

Vite atteint un HMR en 50-200 ms pour les projets typiques. Il utilise les imports de modules ES pour déterminer quels modules sont affectés par un changement, invalide seulement ces modules, et envoie le JavaScript mis à jour au navigateur. Le système de Vite est plus sophistiqué que celui de FLIN -- il préserve l'état des composants à travers les rechargements et gère les graphes de dépendances de modules. Mais il nécessite aussi une étape d'analyse de graphe de modules complexe que FLIN évite entièrement.

Phoenix LiveView (Elixir) prend l'approche la plus proche de celle de FLIN. Le serveur re-rend la vue entière et fait un diff de la sortie HTML, envoyant seulement les fragments changés au navigateur via WebSocket. LiveView atteint cela en 10-50 ms parce que le pattern matching et la gestion binaire d'Erlang sont exceptionnellement rapides. L'approche de FLIN est similaire dans l'esprit mais utilise SSE au lieu de WebSocket pour le canal de rechargement, et un rechargement complet de page au lieu de diff HTML pour le mécanisme de mise à jour.

L'idée clé est que l'architecture mono-fichier de FLIN élimine la partie la plus difficile du HMR : déterminer ce qui a changé et ce qui en dépend. Dans un projet JavaScript multi-modules, un changement d'une fonction utilitaire pourrait affecter des dizaines de composants. Dans FLIN, un changement du fichier signifie recompiler le fichier. L'analyse de dépendances est triviale parce qu'il n'y a pas de graphe de dépendances.


Ceci est la partie 26 de la série « Comment nous avons construit FLIN », documentant comment un CEO à Abidjan et un CTO IA ont construit un langage de programmation à partir de zéro.

Prochain : [27] Async et concurrence dans la VM -- comment FLIN gère les opérations asynchrones, les connexions WebSocket et les tâches concurrentes.

Share this article:

Responses

Write a response
0/2000
Loading responses...

Related Articles

Thales & Claude deblo

Le Step Zero ne suffisait pas : comment valider un constructeur sans valider le runtime a fait tomber toutes les sessions vocales de Déblo l’heure où nous avons livré le streaming caméra temps réel

La phase 14 a livré Déblo Eyes — streaming caméra temps réel via LiveKit vers Gemini Live native audio. Le premier deploy a fait tomber toutes les sessions vocales en production en quatre-vingt-dix secondes parce que notre Step 0 avait validé le constructeur sans exercer le runtime. Le build log de comment Déblo a eu des yeux, ce qu’un pré-vol incomplet a coûté, et quels points de polish ont été livrés ou reportés.

33 min May 20, 2026
debloclaude-opus-4.7claude-codegemini-live +25
Thales & Claude deblo

Le tiret cadratin qui a tué la production : comment un slogan marketing dans un header HTTP a fait tomber le chat de Déblo pendant 24 heures

Deux jours avant la soumission App Store, tout le produit chat de Déblo s’est cassé silencieusement. Pas de spinner, pas de toast, aucune erreur dans l’UI — juste un silence radio. L’incident de 24 heures se résumait à un seul « é » dans la valeur d’un header HTTP qui levait une UnicodeEncodeError avant qu’aucune requête vers OpenRouter ne quitte le backend. Post-mortem d’une fausse hypothèse, d’une trace Sentry, et d’un fix de six lignes qui a débloqué le lancement.

30 min May 19, 2026
debloclaude-opus-4.7claude-codeincident +19
Thales & Claude deblo

Six heures, d’une page blanche à la review Apple — Comment nous avons soumis Déblo à l’App Store, en direct

Marche à marche en direct de la soumission de Déblo à l’App Store iOS en six heures : ce que les validateurs d’Apple ont rejeté (un superscript Unicode), ce que nous avons corrigé (un Promotional Text gaspillé sur des marques tierces), et les rouages de l’ASO iOS que presque tout le monde rate.

30 min May 13, 2026
debloclaude-opus-4.7claude-codeapp-store +16