Un regard pratique sur l'approche compilateur pour la performance web, comparant les frameworks centrés sur le runtime aux sorties générées à la compilation, et proposant un cadre décisionnel simple.

Les utilisateurs décrivent rarement la performance avec des termes techniques. Ils disent que l'app paraît lourde. Les pages mettent une fraction de seconde trop longtemps avant d'afficher quelque chose, les boutons répondent en retard, et des actions simples comme ouvrir un menu, taper dans une barre de recherche ou changer d'onglet saccadent.
Les symptômes sont familiers : un premier chargement lent (UI vide ou partiellement construite), des interactions lentes (clics qui n'arrivent qu'après une pause, défilement haché), et de longues animations ou spinners après des actions qui devraient être instantanées, comme enregistrer un formulaire ou filtrer une liste.
Beaucoup de cela vient du coût d'exécution. En termes simples, c'est le travail que le navigateur doit faire après le chargement de la page pour rendre l'app utilisable : télécharger plus de JavaScript, l'analyser, l'exécuter, construire l'UI, attacher des handlers, puis continuer à faire du travail supplémentaire à chaque mise à jour. Même sur des appareils rapides, il y a une limite à la quantité de JavaScript que l'on peut pousser dans le navigateur avant que l'expérience ne commence à ralentir.
Les problèmes de performance apparaissent aussi tard. Au début, l'app est petite : quelques écrans, données légères, UI simple. Puis le produit grossit. Le marketing ajoute des trackers, le design enrichit les composants, les équipes ajoutent de l'état, des fonctionnalités, des dépendances et de la personnalisation. Chaque changement semble inoffensif pris isolément, mais le travail total s'accumule.
C'est pourquoi les équipes commencent à regarder les idées de performance centrées sur le compilateur. L'objectif n'est généralement pas d'obtenir des scores parfaits. C'est de continuer à livrer sans que l'app ne ralentisse chaque mois.
La plupart des frameworks frontend vous aident à faire deux choses : construire une app et maintenir l'UI synchronisée avec les données. La différence clé est le moment où la seconde partie a lieu.
Avec un framework axé sur le runtime, une grande partie du travail se produit dans le navigateur après le chargement de la page. Vous envoyez un runtime généraliste capable de gérer de nombreux cas : suivre les changements, décider ce qu'il faut mettre à jour et appliquer ces mises à jour. Cette flexibilité est pratique pour le développement, mais cela signifie souvent plus de JavaScript à télécharger, analyser et exécuter avant que l'UI soit prête.
Avec l'optimisation à la compilation, une partie de ce travail est déplacée vers l'étape de build. Au lieu d'envoyer au navigateur un ensemble de règles génériques, l'outil de build analyse vos composants et génère du code plus direct et spécifique à l'app.
Un modèle mental utile :
La plupart des produits réels se situent quelque part entre les deux. Les approches compilateur-first envoient encore du code runtime (routage, fetch de données, animations, gestion d'erreurs). Les frameworks runtime-heavy reposent aussi sur des techniques au build (minification, code-splitting, rendu serveur) pour réduire le travail client. La question pratique n'est pas quel camp a raison, mais quel mix convient à votre produit.
Rich Harris est l'une des voix les plus claires derrière la pensée compilateur-first côté frontend. Son argument est simple : faites plus de travail à l'avance pour que les utilisateurs téléchargent moins de code et que le navigateur fasse moins de travail.
La motivation est pratique. Beaucoup de frameworks runtime-heavy envoient un moteur généraliste : logique de composants, réactivité, diffing, ordonnancement et helpers qui doivent fonctionner pour toutes les apps possibles. Cette flexibilité coûte en octets et en CPU. Même quand votre UI est petite, vous pouvez payer pour un gros runtime.
L'approche compilateur inverse le modèle. Pendant la compilation, le compilateur regarde vos composants réels et génère le code d'update DOM spécifique dont ils ont besoin. Si un libellé ne change jamais, il devient du HTML statique. Si une seule valeur change, seul le chemin de mise à jour pour cette valeur est émis. Au lieu d'envoyer une machine UI générique, vous envoyez la sortie adaptée à votre produit.
Le résultat est souvent simple : moins de code de framework envoyé aux utilisateurs et moins de travail à chaque interaction. Ça se voit particulièrement sur les appareils bas de gamme, où la surcharge runtime devient rapidement perceptible.
Les compromis existent toujours :
Règle pratique : si votre UI est majoritairement connaissable à la compilation, un compilateur peut générer une sortie compacte. Si votre UI est très dynamique ou pilotée par des plugins, un runtime plus lourd peut être plus simple.
L'optimisation à la compilation change l'endroit où le travail se fait. Plus de décisions sont prises pendant le build, et moins il en reste pour le navigateur.
Un résultat visible est la réduction de JavaScript envoyé. Des bundles plus petits réduisent le temps réseau, le temps d'analyse et le délai avant que la page réponde à un tap ou un clic. Sur des téléphones milieu de gamme, cela compte plus que ce que beaucoup d'équipes imaginent.
Les compilateurs peuvent aussi générer des mises à jour DOM plus directes. Quand l'étape de build voit la structure d'un composant, elle peut produire du code qui ne touche que les nœuds DOM qui changent réellement, sans autant de couches d'abstraction à chaque interaction. Ça rend les mises à jour fréquentes plus réactives, en particulier dans les listes, tableaux et formulaires.
L'analyse à la compilation renforce aussi le tree-shaking et la suppression de code mort. Le bénéfice n'est pas seulement des fichiers plus petits : ce sont moins de chemins de code que le navigateur doit charger et exécuter.
L'hydratation est un autre domaine où les choix au build peuvent aider. L'hydratation consiste à transformer une page rendue côté serveur en page interactive en attachant des handlers et en reconstruisant assez d'état dans le navigateur. Si le build peut marquer ce qui demande de l'interactivité et ce qui n'en demande pas, vous réduisez le travail au premier chargement.
En prime, la compilation améliore souvent le scope du CSS. Le build peut réécrire les noms de classes, supprimer les styles inutilisés et réduire les fuites de styles entre composants. Cela diminue les coûts surprises au fur et à mesure que l'UI grandit.
Imaginez un tableau de bord avec des filtres et un grand tableau de données. Une approche compilateur-first peut garder le chargement initial léger, ne mettre à jour que les cellules modifiées après un clic de filtre et éviter d'hydrater des parties de la page qui ne deviennent jamais interactives.
Un runtime plus grand n'est pas automatiquement mauvais. Il apporte souvent de la flexibilité : des patterns décidés à l'exécution, beaucoup de composants tiers et des workflows éprouvés.
Les frameworks runtime-heavy brillent quand les règles d'UI changent souvent. Si vous avez besoin d'un routage complexe, de layouts imbriqués, de formulaires riches et d'un modèle d'état profond, un runtime mature peut faire office de filet de sécurité.
Un runtime aide lorsque vous voulez que le framework gère beaucoup pendant l'exécution de l'app, pas seulement pendant la construction. Cela peut accélérer les équipes au quotidien, même si ça ajoute une surcharge.
Les gains courants incluent un écosystème large, des patterns familiers pour l'état et le fetch de données, d'excellents outils de dev, une extension par plugins plus simple et un onboarding plus fluide quand vous recrutez dans un vivier commun.
La familiarité de l'équipe est un coût réel et un vrai avantage. Un framework légèrement plus lent que votre équipe maîtrise peut battre une approche plus rapide qui nécessite une rééducation, une discipline stricte ou des outils personnalisés pour éviter les pièges.
Beaucoup de plaintes sur la lenteur ne sont pas causées par le runtime du framework. Si votre page attend une API lente, des images lourdes, trop de polices ou des scripts tiers, changer de framework ne résoudra pas le problème central.
Un tableau de bord interne derrière une authentification fonctionne souvent bien même avec un runtime plus lourd, parce que les utilisateurs sont sur des appareils puissants et que le travail est dominé par des tableaux, permissions et requêtes backend.
« Assez rapide » peut être l'objectif adapté au début. Si vous prouvez encore la valeur du produit, gardez une vitesse d'itération élevée, fixez des budgets basiques et n'introduisez la complexité compilateur-first que quand vous avez des preuves que cela importe.
La vitesse d'itération est le temps jusqu'au feedback : à quelle vitesse quelqu'un peut changer un écran, le lancer, voir ce qui casse et corriger. Les équipes qui gardent cette boucle courte livrent plus souvent et apprennent plus vite. C'est pourquoi les frameworks runtime-heavy peuvent sembler productifs au départ : patterns familiers, résultats rapides, beaucoup de comportements intégrés.
Le travail de performance ralentit cette boucle s'il est fait trop tôt ou trop largement. Si chaque PR tourne en débat de micro-optimisation, l'équipe cesse de prendre des risques. Si vous construisez une pipeline complexe avant de savoir ce que sera le produit, les gens passent du temps à lutter contre le tooling au lieu de parler aux utilisateurs.
L'astuce est de s'accorder sur ce que « suffisant » signifie et d'itérer dans cette boîte. Un budget de performance vous donne cette boîte. Il ne s'agit pas de courir après des scores parfaits, mais de limites qui protègent l'expérience tout en permettant le mouvement.
Un budget pratique peut inclure :
Si vous ignorez la performance, vous payez souvent plus tard. Quand un produit grandit, la lenteur se lie aux décisions d'architecture, pas seulement à des réglages mineurs. Une réécriture tardive peut signifier geler des fonctionnalités, rééduquer l'équipe et casser des flux qui marchaient.
Les outils compilateur-first peuvent déplacer ce compromis : vous acceptez des builds un peu plus lents, mais réduisez le travail effectué sur chaque appareil, à chaque visite.
Revenez sur les budgets au fur et à mesure que le produit se confirme. Au début, protégez les bases. Quand le trafic et les revenus augmentent, serrez les budgets et investissez là où les changements déplacent de vrais indicateurs, pas l'ego.
Les débats sur la performance deviennent confus quand personne n'est d'accord sur ce que « rapide » signifie. Choisissez un petit ensemble de métriques, écrivez-les et traitez-les comme un tableau de score partagé.
Un ensemble de départ simple :
Mesurez sur des appareils représentatifs, pas seulement sur un portable de développement. Un CPU rapide, un cache chaud et un serveur local peuvent cacher des délais qui apparaissent sur un téléphone milieu de gamme en réseau mobile moyen.
Restez concret : choisissez deux ou trois appareils qui correspondent aux vrais utilisateurs et exécutez à chaque fois le même flux (écran d'accueil, login, une tâche courante). Faites cela de façon cohérente.
Avant de changer de framework, capturez une baseline. Prenez le build actuel, enregistrez les chiffres pour les mêmes flux et gardez-les visibles. Cette baseline est votre photo « avant ».
Ne jugez pas la performance sur un seul score de laboratoire. Les outils de lab aident, mais ils peuvent récompenser la mauvaise chose (excellent premier chargement) tout en manquant ce que les utilisateurs reprochent (menus saccadés, saisie lente, délais après le premier écran).
Quand les chiffres empirent, n'improvisez pas. Vérifiez ce qui a été livré, ce qui bloquait le rendu et où le temps a été passé : réseau, JavaScript ou API.
Pour faire un choix calme et répétable, traitez le choix de framework et de rendu comme une décision produit. L'objectif n'est pas la meilleure techno, mais le bon équilibre entre performance et rythme dont votre équipe a besoin.
Une thin slice doit inclure les parties compliquées : données réelles, auth et votre écran le plus lent.
Si vous voulez prototyper rapidement cette thin slice, Koder.ai (koder.ai) vous permet de construire des flux web, backend et mobile via le chat, puis d'exporter le code source. Cela aide à tester une route réelle tôt et à garder les expériences réversibles grâce aux snapshots et rollbacks.
Documentez la décision en langage clair, en précisant ce qui vous ferait la revoir (croissance du trafic, part mobile, objectifs SEO). Cela rend le choix durable quand l'équipe évolue.
Les décisions de performance foirent souvent quand les équipes optimisent ce qu'elles voient aujourd'hui, pas ce que les utilisateurs ressentiront dans trois mois.
Une erreur est de sur-optimiser dès la première semaine. Une équipe passe des jours à gagner des millisecondes sur une page qui change encore tous les jours, alors que le vrai problème est que les utilisateurs n'ont pas encore les bonnes fonctionnalités. Au début, accélérez l'apprentissage d'abord. Verrouillez les travaux de performance profonds une fois les routes et composants stabilisés.
Une autre erreur est d'ignorer la croissance du bundle jusqu'à ce que ça fasse mal. Les choses vont bien à 200 KB, puis quelques ajouts « petits » plus tard vous expédiez des mégaoctets. Une habitude simple aide : suivez la taille du bundle dans le temps et traitez les sauts brutaux comme des bugs.
Les équipes ont aussi tendance à tout rendre côté client, même quand certaines routes sont majoritairement statiques (pages pricing, docs, onboarding). Ces pages peuvent souvent être livrées avec bien moins de travail côté appareil.
Un tueur plus discret est d'ajouter une grosse bibliothèque UI pour la commodité sans mesurer son coût dans le build de production. La commodité est valide. Soyez juste clair sur ce que vous payez en JS supplémentaire, CSS supplémentaire et interactions plus lentes sur les téléphones milieu de gamme.
Enfin, mélanger les approches sans frontières claires crée des apps difficiles à déboguer. Si la moitié de l'app suppose des updates générés par compilateur pendant que l'autre moitié repose sur de la magie runtime, vous vous retrouvez avec des règles floues et des échecs confus.
Quelques garde-fous qui tiennent dans de vraies équipes :
Imaginez une équipe de 3 personnes construisant un SaaS de planification et facturation. Il a deux visages : un site marketing public (landing, pricing, docs) et un dashboard authentifié (calendrier, factures, rapports, réglages).
Sur la voie runtime-first, ils choisissent une configuration runtime-heavy parce qu'elle rend les changements UI rapides. Le dashboard devient une grosse app client avec composants réutilisables, une librairie d'état et des interactions riches. L'itération est rapide. Avec le temps, le premier chargement commence à peser sur les téléphones milieu de gamme.
Sur la voie compilateur-first, ils optent pour un framework qui pousse plus de travail à la compilation pour réduire le JavaScript client. Les flux communs comme ouvrir le dashboard, changer d'onglet et rechercher sont plus réactifs. Le compromis est que l'équipe doit être plus délibérée sur les patterns et le tooling, et que certains trucs runtime faciles ne sont pas aussi plug-and-play.
Ce qui déclenche le changement n'est presque jamais du goût. C'est la pression de la réalité : des pages plus lentes nuisent aux inscriptions, plus d'utilisateurs arrivent sur des appareils bas de gamme, des clients enterprise demandent des budgets prévisibles, le dashboard reste ouvert tout le temps et la mémoire compte, ou le support signale des lenteurs sur des réseaux réels.
Une option hybride gagne souvent. Gardez les pages marketing légères (rendu serveur ou essentiellement statique, code client minimal) et acceptez plus de runtime dans le dashboard là où l'interactivité le justifie.
En utilisant les étapes de décision : ils nomment les parcours critiques (inscription, première facture, reporting hebdo), les mesurent sur un téléphone milieu de gamme, fixent un budget et choisissent l'hybride. Par défaut compilateur-first pour les pages publiques et les composants partagés, runtime-heavy uniquement là où cela améliore clairement la vitesse d'expérimentation.
La façon la plus simple de concrétiser ces idées est une boucle hebdomadaire courte.
Commencez par un scan de 15 minutes : la taille du bundle augmente-t-elle, quelles routes paraissent lentes, quels sont les plus gros morceaux UI sur ces routes (tables, charts, éditeurs, cartes), et quelles dépendances pèsent le plus. Puis choisissez un goulot que vous pouvez corriger sans réécrire votre stack.
Pour cette semaine, gardez ça petit :
Pour garder les choix réversibles, tracez des frontières claires entre routes et fonctionnalités. Préférez des modules interchangeables (charts, éditeurs riche, SDKs analytics) que vous pouvez remplacer plus tard sans toucher toute l'app.
La plupart du temps, ce n'est pas que le réseau — c'est le coût d'exécution : le navigateur qui télécharge, analyse et exécute du JavaScript, construit l'UI et effectue du travail supplémentaire à chaque mise à jour.
C'est pourquoi une app peut donner une impression de lourdeur même sur un bon ordinateur une fois que la charge JavaScript devient importante.
Ils visent le même objectif (faire moins côté client), mais le mécanisme diffère.
Ça veut dire que le framework peut analyser vos composants à la compilation et produire du code adapté à votre application, plutôt que d'envoyer un gros moteur UI générique.
Le bénéfice pratique est généralement des bundles plus petits et moins de travail CPU pendant les interactions (clics, saisie, défilement).
Commencez par :
Mesurez toujours sur des appareils représentatifs et répétez le même flux utilisateur pour comparer les builds.
Oui, parfois. Mais si votre app attend des APIs lentes, des images lourdes, trop de polices ou des scripts tiers, changer de framework ne supprimera pas ces goulots d'étranglement.
Considérez le choix du framework comme un levier parmi d'autres : commencez par confirmer où passe le temps — réseau, CPU JavaScript, rendu ou backend.
Choisissez un runtime plus lourd quand vous avez besoin de flexibilité et d'une vitesse d'itération élevée :
Si le runtime n'est pas votre goulot d'étranglement, la commodité peut valoir les octets supplémentaires.
Un défaut par défaut simple :
L'approche hybride marche souvent le mieux : écrivez des frontières claires pour éviter un mélange confus d'hypothèses.
Utilisez un budget qui protège le ressenti utilisateur sans bloquer la livraison. Par exemple :
Les budgets sont des garde-fous, pas un concours de scores parfaits.
L'hydratation est le travail consistant à rendre interactive une page rendue côté serveur en attachant des handlers et en reconstruisant assez d'état dans le navigateur.
Si vous hydratez trop, le premier chargement peut paraître lent même si le HTML s'affiche vite. Les outils de build peuvent parfois réduire l'hydratation en marquant ce qui nécessite vraiment d'être interactif.
Un bon « thin slice » inclut les vraies complications :
Pour prototyper cette tranche, Koder.ai peut vous aider à construire le flux web + backend via le chat et exporter le code source, afin que vous puissiez mesurer et comparer tôt sans vous engager dans une réécriture complète.