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é.

Thales & Claude | March 30, 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