Veille

Quel framework frontend est le plus rapide ?

  • Date de l’événement 07 Mar. 2024
  • Temps de lecture min.

Cet article est le troisième volet d’une série, à laquelle vous pouvez accéder via les liens suivants :

  1. Comment choisir la bonne architecture front-end ?
  2. Quel framework frontend choisir ?

Donc, si vous envisagez de déterminer le meilleur framework front-end pour vos besoins, je vous recommande également de lire les articles précédents.

Dans cet article, notre objectif principal sera de comparer les performances des frameworks suivants :

  • Rendu côté client (CSR) :
    • Angulaire
    • Réagir
    • Solide
    • Vue
  • Rendu côté serveur (SSR) :
    • Astro
    • Astro + Réagir
    • Gatsby
    • Suivant (routeur d'application)
    • Suivant (routeur de pages)
    • Nuxt
    • Qwik
    • Remixer
    • Kit Svelté

 

Tout au long de l’article, nous aborderons les sujets suivants :

  • Analyse comparative des temps de chargement des pages identiques implémentées dans divers frameworks.
  • Évaluer les performances de réactivité de ces frameworks.
  • Fournir un résumé et tirer des conclusions concernant les frameworks les plus rapides.

Introduction

Ce benchmark se concentre sur la vitesse de chargement initiale des pages. Quand je dis « premier chargement », je veux dire que la plupart des frameworks frontend implémentent le routage frontend, ce qui a l'avantage de ne pas nécessiter le téléchargement de tous les éléments dès le début.

Cependant, du point de vue du classement Google, le score Lighthouse est crucial. Ainsi, faire des efforts pour améliorer votre score Lighthouse peut conduire à de meilleurs taux de conversion et à un meilleur référencement (Search Engine Optimization).

Pour les tests, j'ai recréé la page d'accueil de https://www.smile.eu/fr , car je souhaitais utiliser une page avec du contenu existant. Le score Lighthouse actuel de cette page est loin d’être parfait, ce qui correspond à l’objectif de cette comparaison.

L'objectif principal ici est de comparer les différents frameworks et de voir si l'un surpasse les autres.

Vous pouvez accéder à tout le code de ce référentiel .

Examinons maintenant les résultats de chaque scénario, en utilisant l'approche la plus optimale pour présenter le contenu en vue d'une comparaison équitable.

Glossaire

  • FCP : First Contentful Paint - First Contentful Paint marque le moment où le premier texte ou image est peint.
  • LCP : Largest Contentful Paint - Largest Contentful Paint marque le moment où le plus grand texte ou image est peint.
  • TBT : Total Blocking Time - La somme de toutes les périodes de temps entre FCP et Time to Interactive, lorsque la durée d'une tâche dépasse 50 ms, exprimée en millisecondes.
  • CLS : Cumulative Layout Shift - Cumulative Layout Shift mesure le mouvement des éléments visibles dans la fenêtre.
  • SI : Speed Index - Speed Index montre à quelle vitesse le contenu d'une page est visiblement rempli.

Page statique complète

La page n'a aucune interaction, c'est uniquement du HTML, du CSS, des polices, des images... Etc.

Résultats (avec Chrome 116.0.5845.96) :

CadresTaperScore
AngulaireRSE68
AstroRSS67
Astro + RéagirRSS67
GatsbyRSS68
Suivant (routeur d'application)RSS67
Suivant (routeur de pages)RSS68
NuxtRSS68
QwikRSS68
RéagirRSE67
RemixerRSS68
SolideRSE67
Kit SveltéRSS68
VueRSE67

Résultats (avec Chrome 116.0.5845.96) : On peut observer que les scores Lighthouse vont de 67 à 68, indiquant qu'ils sont tous assez proches en valeur. Le score Lighthouse peut parfois présenter de légères variations selon plusieurs lots de tests, ce qui rend difficile la déclaration définitive d'un framework comme supérieur à un autre.

Maintenant, concentrons-nous sur la taille de la page. Dans tous ces frameworks, les tailles CSS, d'image et de police restent cohérentes, ne différant qu'en termes de tailles de document et de JavaScript.

Voici un tableau illustrant ces différences (triés par taille totale) :

Voici quelques points notables à considérer :

  • La taille du document des frameworks CSR (Client Side Rendering) (Angular, React, Solid et Vue) est minime, à seulement environ 1 Ko, car il est en grande partie vide en raison du contenu généré côté client.
  • Certains frameworks, tels qu'Astro, Qwik, Remix et Sveltekit, n'incluent aucun fichier JS.
  • La taille JS semble être de 0 dans certains cas, mais en réalité, du JavaScript est encore intégré dans le document. C'est pourquoi la taille du document varie selon les frameworks SSR (Server Side Rendering).

Forts de ces observations, nous sommes prêts à approfondir notre analyse.

Page avec peu d'interactions

Dans ce scénario particulier, j'ai introduit certaines interactions JavaScript exclusivement dans l'en-tête et le pied de page de la page.

Résultats (avec Chrome 116.0.5845.96) :

CadresTaperScore
AngulaireRSE67
AstroRSS67
Astro + RéagirRSS66
GatsbyRSS67
Suivant (routeur d'application)RSS67
Suivant (routeur de pages)RSS68
NuxtRSS67
QwikRSS68
RéagirRSE67
RemixerRSS67
SolideRSE67
Kit SveltéRSS66
VueRSE67

Dans ce scénario, on observe un peu plus de disparités dans les scores Lighthouse, allant de 66 à 68. Les scores sont généralement un peu plus faibles, mais ils oscillent toujours autour d’une fourchette similaire.

Voici encore un nouveau graphique illustrant ces différences :

Dans ce scénario, on observe un peu plus de disparités dans les scores Lighthouse, allant de 66 à 68. Les scores sont généralement un peu plus faibles, mais ils oscillent toujours autour d’une fourchette similaire.

Voici encore un nouveau graphique illustrant ces différences :

Page avec interactions

Dans ce scénario, chaque partie de la page est devenue interactive et une carte Leaflet est chargée au milieu de la page. Il est important de noter que les données de la carte ne sont pas récupérées mais sont stockées de manière statique dans JavaScript.

Résultats (avec Chrome 116.0.5845.96) :

CadresTaperScore
AngulaireRSE66
AstroRSS66
Astro + RéagirRSS67
GatsbyRSS67
Suivant (routeur d'application)RSS66
Suivant (routeur de pages)RSS66
NuxtRSS66
QwikRSS68
RéagirRSE67
RemixerRSS66
SolideRSE67
Kit SveltéRSS65
VueRSE66

Dans ce scénario, comme dans le précédent, les scores Lighthouse ont globalement légèrement diminué (sauf pour Qwik).

Pour potentiellement constater une différence plus substantielle entre les frameworks, nous devrons peut-être introduire la récupération de données à partir d'un backend. C’est le but du scénario à venir.

Page avec interactions et récupération de données

Dans ce scénario, j'ai développé le précédent en incorporant cinq appels d'API pour récupérer des données :

  • Quatre appels API sont utilisés pour charger les données du contenu, les données étant récupérées sur le serveur pour les frameworks SSR et sur le client pour les frameworks CSR.
  • Un appel API est dédié au chargement des données de la carte, et cet appel est toujours exécuté côté client.
  • Pour imiter une réponse API plus lente, j'ai introduit un délai d'une seconde pour chaque appel API.
  • Les quatre appels API pour le contenu sont indépendants les uns des autres, ce qui permet de les récupérer en parallèle.
  • Dans la mesure du possible, j'ai testé les techniques de rendu SSR et SSG pour les frameworks SSR.

 

Résultats (avec Chrome 116.0.5845.96) :

CadresTaperScore
AngulaireRSE67
AstroRSE66
Astro + RéagirSSG67
GatsbyRSS67
GatsbySSG67
Suivant (routeur d'application)RSS67
Suivant (routeur d'application)SSG68
Suivant (routeur de pages)RSS67
Suivant (routeur de pages)SSG66
NuxtSSG67
QwikSSG68
RéagirRSE67
RemixerRSS66
SolideRSE67
Kit SveltéSSG66
VueRSE66

Dans le dernier scénario, malgré l'introduction du chargement, les scores Lighthouse n'ont pas sensiblement diminué par rapport au scénario précédent. Cette observation est vraie à la fois pour CSR, où la récupération des données s'effectue sur le client, et SSR, où la récupération des données est effectuée sur le serveur, même lorsque les réponses de l'API sont retardées d'une seconde (ce qui entraîne un temps de chargement perçu plus long pour les utilisateurs).

Cela conduit à une conclusion importante : les scores Lighthouse se concentrent principalement sur les performances du frontend et dépendent moins de l’efficacité de vos API.

Dans le scénario à venir, vous avez décidé d'introduire une tâche de calcul importante dans JavaScript pour, espérons-le, produire des différences de performances plus perceptibles.

Page avec calcul long

Dans le dernier scénario, une longue tâche de calcul a été ajoutée, qui implique une très longue boucle qui prend environ 10 secondes sur mon ordinateur.

Ce temps de traitement prolongé révélera probablement des différences de performances substantielles.

Il est essentiel de noter que ce calcul est exécuté sur le client pour les frameworks CSR et sur le serveur pour les frameworks SSR (sans hydratation).

Résultats (avec Chrome 116.0.5845.96) :

CadresTaperScore
AngulaireRSE26
AstroRSS66
Astro + RéagirRSS67
GatsbyRSS62
Suivant (routeur d'application)RSS62
Suivant (routeur de pages)RSS61
NuxtRSS67
QwikRSS68
RéagirRSE32
RemixerRSS60
SolideRSE26
Kit SveltéRSS30
VueRSE26

Dans ce scénario, nous commençons en effet à observer des différences significatives :

  • Les cadres de RSE affichent des scores inférieurs, allant de 26 à 32, avec des variations selon les différents lots de tests, soulignant des distinctions tangibles entre ces cadres.
  • Dans les cas SSR, il y a une baisse des scores d'environ 5 points en raison d'une augmentation de la métrique SI. Cela suggère qu’un TTFB (Time To First Byte) prolongé peut avoir un impact mineur sur le score Lighthouse par rapport au temps passé côté client.
  • Remix ne peut pas effectuer SSG, mais Gatsby et Next le peuvent, ce qui signifie que dans certains cas, ces frameworks peuvent passer à SSG pour atténuer l'impact du long calcul.
  • Les frameworks SSG, à l'exception de Sveltekit, ne subissent aucun impact significatif du calcul puisqu'il est effectué pendant le processus de construction. Cependant, le score de Sveltekit est similaire à celui des frameworks RSE, car il effectue principalement le long calcul côté client.

Cet exemple démontre effectivement qu'avoir un calcul long sur le serveur est généralement plus avantageux. Cependant, dans la plupart des projets réels, un scénario aussi précis peut ne pas se produire. Le scénario le plus courant dans lequel JavaScript consomme du temps est celui du rendu de vos composants. Passons au scénario suivant.

Page avec une longue hydratation

Dans ce scénario, l'objectif est d'avoir le temps consommé lors du processus de rendu, qui affecte principalement les frameworks SSR. Dans la plupart de ces frameworks, le rendu s'effectue côté serveur. Cependant, lors du chargement de la page, le rendu se produit à nouveau côté client, un processus appelé hydratation.

Ce scénario vise à illustrer l'impact du temps de rendu sur les performances des frameworks SSR lorsque l'hydratation est impliquée.

Résultats du framework SSR (avec Chrome 116.0.5845.96) :

CadresTaperScore
Astro (identique au précédent)SSG66
Astro + RéagirSSG36
Astro + React (en utilisant le client : visible)SSG68
GatsbyRSS32
Suivant (routeur d'application, identique au précédent)RSS62
Suivant (routeur de pages)RSS31
NuxtSSG36
QwikSSG68
RemixerRSS31
Kit SveltéSSG33

Dans ce scénario, plusieurs observations importantes peuvent être faites :

  • L'impact de l'hydratation est évident et réduit considérablement les scores des techniques de rendu SSR et SSG à un niveau similaire à celui des cadres CSR. En effet, le long calcul s'effectue uniquement sur le client pour SSG, tandis que pour SSR, il se produit à la fois sur le serveur et sur le client.
  • Astro sans React utilise du JS simple, évitant ainsi le besoin d'hydratation, ce qui n'entraîne aucun impact significatif sur le score Lighthouse.
  • La directive client:visible dans Astro peut être utilisée pour charger paresseusement des composants de framework. Cela signifie que le calcul long n'a lieu que lorsque le composant entre dans la fenêtre, ce qui n'a aucun effet néfaste sur le score Lighthouse (dans ce cas).
  • Dans le cas de Next (en utilisant le routeur d'application), le long calcul est placé dans un composant serveur React, qui n'est pas hydraté. De ce fait, le calcul s’effectue exclusivement côté serveur, minimisant ainsi l’impact de l’hydratation des composants.
  • La technique de « resumabilité » de Qwik garantit qu'aucun calcul n'a lieu côté client car il a déjà été exécuté sur le serveur, optimisant ainsi davantage les performances.

Ces résultats mettent en lumière les différentes approches et leurs implications sur les performances du framework frontend dans diverses circonstances.

Benchmark de réactivité
But

Dans cette section, nous nous concentrerons sur l’analyse comparative de la réactivité du framework.
Cette activité a lieu après le chargement de la page, par exemple lorsqu'un utilisateur interagit avec la page en cliquant sur un bouton pour afficher quelque chose. Notre objectif est d'éviter les tâches longues, celles qui prennent plus de 50 millisecondes, afin de garantir la fluidité de la page.
L'objectif de ce benchmark est d'évaluer les performances du framework dans la gestion de cette tâche, en particulier le temps nécessaire au framework pour mettre à jour le DOM en réponse à un changement d'état.
Une façon d’évaluer ce coût consiste à calculer le temps nécessaire au framework pour une tâche simple, telle que l’incrémentation d’un compteur. Dans ce cas, la majorité du temps consacré à cette action est, en fait, le temps nécessaire au framework pour restituer et mettre à jour le DOM, tandis que le coût de la partie code personnalisé (l'opération d'incrémentation) est négligeable.
Cependant, mesurer et comparer cela peut être difficile car cette action est très rapide. Un moyen plus simple de faire des comparaisons consiste à compter le nombre de fois qu'un framework peut être rendu en une seconde.

Mise en œuvre technique

L'aspect difficile ici est de mettre à jour l'état de l'application et de permettre au framework d'effectuer le rendu, puis de déclencher une nouvelle mise à jour de l'état lorsque le rendu est terminé, et ainsi de suite. En raison de la nature monothread de JavaScript, il n'est pas possible de mettre à jour l'état dans une boucle. Dans un tel scénario, le framework ne s'affichera probablement que lorsque la boucle sera terminée, mettant à jour le DOM avec la version finale du compteur. Ce n'est pas ce que nous voulons car nous voulons compter le nombre de rendus.

Nous souhaitons également utiliser la même technique pour tous les frameworks afin de garantir une comparaison équitable. Par exemple, il n'est pas possible d'utiliser useEffect de React pour déclencher un nouvel incrément une fois le rendu terminé.
Une façon d'y parvenir consiste à utiliser quelque chose comme setTimeout(increment, 0). L'appel de setTimeout reporte l'exécution de la fonction d'incrémentation jusqu'à ce que le thread principal soit disponible. Cependant, le problème avec setTimeout est qu'il n'est pas assez rapide ; il faut environ 4 millisecondes pour déclencher un nouvel incrément.

Vous pouvez le voir dans l'enregistrement de l'onglet Performances de Google Devtools :

Ce que nous aimerions, c'est quelque chose de similaire à la fonction node setImmediate. Nous pouvons obtenir un effet similaire en utilisant MessageChannel. Voici l'enregistrement de l'onglet performances démontrant toutes les mises à jour :


Avec cette solution, nous sommes désormais prêts à comparer la réactivité de différents frameworks.

Résultats

Je n'ai pas implémenté le benchmark de réactivité pour tous les frameworks car Next, Gatsby, Remix et d'autres s'appuient tous sur React. Je ne l'ai implémenté que lorsque le framework frontend était autre chose que React.
Voici donc le classement du nombre de rendus que ces frameworks peuvent effectuer en une seconde, du meilleur au pire :

CadreRendre
JS natif (Astro)~174 000
Solide~148400
Svelte~123800
Vue~77400
Qwik~70900
Réagir optimisé~34800
Angulaire~3100
Réagir non optimisé~2200

Calculons un score en fonction du score maximum :

CadreScore
JS natif (Astro)100
Solide85
Svelte71
Vue44
Qwik41
Réagir optimisé20
Angulaire2
Réagir non optimisé1

Voici quelques points remarquables :

  • Il est assez rassurant de voir que l’implémentation native de JavaScript est la plus performante.
  • Le système de réactivité Solid est conçu en mettant l'accent sur la vitesse (vous pouvez en savoir plus ici : https://www.solidjs.com/guides/reactivity)
  • Svelte, bien qu'il ne s'agisse pas exactement d'un framework, se compile en JavaScript natif de manière efficace.
  • Les performances de React peuvent varier considérablement, allant du framework le moins performant à plus de 10 fois meilleur, selon la façon dont vous définissez l'état dans votre application.
  • Les résultats d'Angular sont médiocres en raison de la nécessité de réintégrer les messages de MessageChannel dans le flux Angular à l'aide de NgZone.

Vous pouvez également vous référer à cette page de référence, qui compare différents cadres dans différents scénarios, mais les conclusions globales restent cohérentes.

Résumé

Mondial

Voici quelques points généraux à considérer avant d’approfondir les conclusions de chaque cadre :

  • Lighthouse enregistre principalement les performances du front-end et les requêtes du back-end ont un impact minimal sur le score.
  • Cela implique que vous devez vous concentrer sur l'optimisation de votre backend de manière indépendante, soit par vous-même, soit avec d'autres outils, pour garantir que votre serveur est rapide et offre la meilleure expérience utilisateur.
  • Dans l’ensemble, les frameworks SSR (Server-Side Rendering) fonctionnent légèrement mieux que les frameworks CSR (Client-Side Rendering), bien que la différence ne soit pas substantielle.
  • Cela suggère que les cadres RSE restent des options viables lors de la création d'applications telles que les systèmes de back-office, les intranets, les extranets, les applications connectées, etc. (mais évitez d'utiliser les cadres RSE si le référencement est un problème).
  • Bien qu'il n'y ait pas de variations significatives entre les cadres RSE dans le benchmark de chargement de page, il existe des différences notables en termes de réactivité.

 

Qwik

Compte tenu des résultats, le framework Qwik semble fonctionner exceptionnellement bien, en particulier lorsque vous regroupez tous les scores du scénario Lighthouse en un seul endroit :

ScénarioScore
Page statique complète68
Page avec peu d'interactions68
Page avec interactions68
Page avec interactions et récupération de données68
Page avec calcul long68
Page avec une longue hydratation68

La capacité du framework à compenser une programmation sous-optimale est assez impressionnante.
Même si le système de réactivité du framework n'est pas le plus rapide (avec une note de 41 sur 100), il reste suffisamment rapide.

 

Astro

Astro se distingue également par son architecture insulaire, qui vous permet de choisir le framework que vous souhaitez pour des composants spécifiques là où c'est le plus avantageux.

Grâce aux directives Astro, telles que client:visible, vous pouvez charger les parties du framework uniquement lorsqu'elles sont nécessaires.

Voici les résultats consolidés pour Astro lors de l’utilisation de cette directive :

ScénarioScore
Page statique complète67
Page avec peu d'interactions66
Page avec interactions67
Page avec interactions et récupération de données67
Page avec calcul long67
Page avec une longue hydratation68

La distinction entre Astro et Qwik réside dans le fait que, pour Astro, le processus d'hydratation étendu se produira toujours sur le frontend lorsque le composant entre dans la fenêtre.

Vous pouvez également rencontrer un défi lorsqu'il s'agit de permettre à plusieurs composants de l'île de communiquer entre eux dans Astro. Cependant, ce problème peut être résolu à l'aide d'outils tels que les magasins Astro nano ou une bibliothèque d'état telle que Redux, entre autres.

Il est important de noter que la réactivité du framework dépendra du framework spécifique que vous choisirez en combinaison avec Astro.

 

Suivant / Gatsy / Remix / Nuxt

Voici un résumé des partitions de Next, Gatsby, Remix et Nuxt :
 

ScénarioSuivant (routage des applications)Suivant (routage des pages)GatsbyRemixerNuxt
Page statique complète6768686868
Page avec peu d'interactions6768676767
Page avec interactions6666676666
Page avec interactions et récupération de données67 (ssr) / 68 (ssg)67 (ssr) / 66 (ssg)67 (ssr) / 67 (ssg)66 (ssr)67 (ssg)
Page avec calcul long62 (ssr) / 68 (ssg)61 (ssr) / 67 (ssg)62 (ssr) / 67 (ssg)60 (ssr)67 (ssg)
Page avec une longue hydratation6231323136

Sur la base de ces résultats, nous pouvons conclure que dans la plupart des scénarios, ces frameworks présentent des niveaux de performances similaires.

Next se démarque lorsqu'il utilise le routage d'applications (et, par conséquent, le composant React Server) et fonctionne mieux dans les situations où un composant serveur doit effectuer des calculs complexes. Cependant, dans la pratique, de tels cas peuvent ne pas être très courants car ces calculs reposent souvent sur l'état du frontend et doivent être recalculés côté client.

Néanmoins, si vous rencontrez des problèmes de performances, utiliser Next avec React Server Side Rendering pourrait être un choix judicieux. Il a non seulement le potentiel d’améliorer les performances dans des scénarios spécifiques, mais réduit également le nombre global de composants hydratés. Par conséquent, si vous souhaitez utiliser React avec le rendu côté serveur, Next est probablement l'un des meilleurs choix.

 

SvelteKit

Résultats du score Lighthouse pour SvelteKit :
 

ScénarioScore
Page statique complète68
Page avec peu d'interactions66
Page avec interactions65
Page avec interactions et récupération de données66
Page avec calcul long30 (ssg)
Page avec une longue hydratation33

J'ai été quelque peu surpris par les résultats. En général, ils sont légèrement inférieurs à ceux des autres frameworks, et SvelteKit n'est pas capable de sérialiser des calculs approfondis généralement réservés au backend. Même si cela n’arrive pas souvent, l’option reste indisponible.

Cependant, le système de réactivité est très efficace, avec une note de 71 sur 100. Globalement, il est assez comparable aux frameworks mentionnés ci-dessus.

 

Réagir / Vue / Angulaire / Solide

Voici un résumé des scores de ces frameworks :
 

ScénarioAngulaireRéagirSolideVue
Page statique complète68676767
Page avec peu d'interactions67676767
Page avec interactions66676766
Page avec interactions et récupération de données67676766
Page avec calcul long26322626

Il est difficile d'identifier des différences significatives ici ; les résultats sont largement cohérents.

La seule exception notable est que Solid possède le système réactif le plus rapide, obtenant un score de 85/100 et s'imposant comme le meilleur framework CRS réactif.

Conclusion

En conclusion, il existe relativement peu de différences, ce qui rend le choix du cadre moins critique pour la performance.

De plus, si vous rencontrez des problèmes de performances, vous trouverez probablement des solutions dans le cadre que vous utilisez.

Voici néanmoins les résultats finaux :

  • Qwik se démarque par son impressionnant système d'hydratation réutilisable, car il semble optimisé par défaut. Cela pourrait être un excellent choix pour les projets qui nécessitent de tout créer à partir de zéro et ne dépendent pas beaucoup de bibliothèques externes. Il convient de noter que l'écosystème et la communauté Qwik sont relativement nouveaux.
  • Astro offre de solides performances et vous permet de sélectionner votre framework préféré. Cependant, son architecture insulaire pourrait ne pas convenir à tous les projets. Pensez à l’utiliser si vous n’avez besoin d’interactivité que dans des parties spécifiques de votre site Web.
  • Le prochain choix serait probablement le choix par défaut pour les projets qui n'entrent pas dans les catégories susmentionnées.
  • Solid possède la meilleure réactivité, mais comme Qwik, son écosystème est encore émergent. Cela pourrait valoir la peine d'être exploré dans des scénarios où le référencement n'est pas une préoccupation majeure (bien que SolidStart propose SSR, il est toujours en version bêta) et où vous ne comptez pas beaucoup sur des bibliothèques externes.

Tony Cabaye

Expert technique