Turbopack est actuellement en version alpha. Il n'est pas encore prêt pour une utilisation en production. Mais NextJS permet d'utiliser Turbopack avec next dev --turbo alors le serveur de développement NextJS v13 est maintenant alimenté par Turbopack.
Dirigé par Tobias Koppers, le créateur de Webpack, Turbopack ne regroupe que le minimum de ressources nécessaires au développement, le temps de démarrage est donc extrêmement rapide. Sur une application comportant 3 000 modules, le démarrage de Turbopack prend 1,8 seconde. Vite prend 11,4 secondes et Webpack 16,5 secondes. Turbopack prend en charge dès le démarrage les composants de serveur, TypeScript, JSX, CSS, etc. De nombreuses fonctionnalités ne sont pas encore prises en charge.
L'architecture de Turbopack tire les leçons d'outils comme Turborepo et Bazel de Google, qui se concentrent tous deux sur l'utilisation de caches pour ne jamais faire deux fois le même travail. Turbopack est construit sur Turbo : un framework open source de mémorisation incrémental pour Rust. Turbo peut mettre en cache le résultat de n'importe quelle fonction du programme. Lorsque le programme est exécuté à nouveau, les fonctions ne seront exécutées que si leurs entrées ont changé. Cette architecture granulaire permet à votre programme de sauter de grandes quantités de travail, au niveau de la fonction.
Dans divers documents marketing de Vercel, on retrouve la phrase « Turbopack est 10x plus rapide que Vite ». Cette phrase est répétée y compris un tweet, un article de blog et des courriels de marketing envoyés aux utilisateurs de Vercel. Les graphiques de benchmark sont également inclus dans la documentation de Turbopack, montrant à l'origine que Next 13 avec Turbopack est capable d'effectuer un React Hot-Module Replacement (HMR) en 0,01s alors qu’avec Vite, cela prend 0,09s.
Initialement, Vercel n'a pas inclus de liens vers les benchmarks qu'ils ont utilisés pour produire ces chiffres dans les documents marketing ou la documentation. Le développeur Evan You dans sa quête de vérité a décidé de vérifier les affirmations avec un benchmark utilisant le tout nouveau Next 13 et Vite 3.2. L'essentiel de sa méthodologie consiste à comparer les performances de HMR en mesurant le delta entre les deux horodatages suivants :
- le moment où un fichier source est modifié, enregistré via un processus Node.js séparé surveillant les changements de fichiers ;
- l'heure à laquelle le composant React mis à jour est rendu, enregistrée via un appel à Date.now() directement dans la sortie de rendu du composant.
Méthodologie
- Les deux projets sont créés à partir des commandes suivantes :
npx create-next-app@latest ;
npm init vite@latest # select React preset - genFiles.(m)js est exécuté dans chaque projet pour générer 1000 composants. Tous les composants sont importés dans le composant racine de l'application (dans le cas de Next, le composant racine de la page) et rendus ensemble. Cette étape est déjà réalisée et les fichiers sont déjà archivés, mais le script est inclus pour référence
- Pour Next, app/page.js possède la directive "use client", ce qui lui permet d'effectuer le rendu en mode client. Cela est nécessaire pour assurer une comparaison correcte, car les composants du serveur entraînent une surcharge HMR non négligeable (4 fois plus lente)
- Pour Vite, vite-plugin-swc-react-refresh est utilisé pour que la transformation React JSX & HMR utilise swc au lieu de Babel. La raison pour laquelle le plugin React par défaut de Vite utilise Babel est que l'utilisation de swc entraîne 58 Mo de poids d'installation supplémentaire (alors que Vite lui-même fait 19 Mo) pour une amélioration marginale de HMR. Cependant, pour les besoins de l'évaluation comparative, Evan You utilise les mêmes transformations que celles utilisées par turbopack afin que la comparaison soit axée sur les mécanismes HMR des deux outils
- pour chaque projet, nous exécutons watch.(m)js dans un processus Node séparé pour obtenir l'horodatage exact du changement de fichier. Ceci est utilisé pour marquer le début de HMR
- Démarrez les projets (vite et next dev --turbo), puis éditez les fichiers suivants pour tester HMR :
- Next: app/page.js (root) and app/comp0.jsx (leaf)
- Vite: src/App.jsx (root) and src/components/comp0.jsx (leaf)
Les composants édités affichent tous Date.now() dans leur sortie. L'horodatage final rendu dans le DOM est utilisé pour marquer l'achèvement de HMR. Le benchmark mesure également les chiffres dans deux cas différents :
- le cas "root", où le composant importe 1 000 composants enfants différents et les rend également ensemble ;
- le cas "leaf", où le composant est importé par la racine mais n'a pas d'importations ou de composants enfants propres.
Nuances
Avant de passer aux chiffres, il y a quelques nuances supplémentaires qui méritent d'être mentionnées :
- si Next utilise React Server Components (RSC) ;
- si Vite utilise SWC au lieu de Babel pour les transformations React.
React Server Components
Next 13 a introduit un changement architectural majeur dans la mesure où les composants sont désormais des composants serveur par défaut, à moins que l'utilisateur n'opte explicitement pour le mode client avec la directive use client. Non seulement c'est le mode par défaut, mais la documentation de Next recommande également aux utilisateurs de rester en mode serveur autant que possible pour améliorer les performances de l'utilisateur final.
Le benchmark initial d’Evan You a mesuré les performances HMR de Next 13 avec les composants root et leaf en mode serveur. Le résultat a montré que Next 13 était en fait plus lent dans les deux cas, et la différence était significative pour les composants leaf.
- Enregistré sur 5 cycles
- Temps en ms
- Testé sur Mackbook Pro M1
En ajoutant la directive use client au composant root de Next pour passer en mode client, Next HMR s'améliore de manière significative, allant 2x plus vite que Vite :
Transformations SWC vs. Babel
L’objectif est de faire en sorte que le benchmark se concentre uniquement sur la différence de performance HMR. Les transformations React HMR et JSX ne sont pas des fonctionnalités couplées aux outils de construction. Elles peuvent être effectuées via Babel (basé sur js) ou SWC (basé sur rust). Esbuild peut également transformer JSX, mais ne supporte pas HMR.
SWC est significativement plus rapide que Babel (20x en mono-fil, 70x en multi-cœurs).
La raison pour laquelle Vite utilise actuellement Babel par défaut est un compromis entre la taille de l'installation et l'aspect pratique. La taille de l'installation de SWC est assez lourde (58MB dans node_modules alors que Vite lui-même ne fait que 19MB), et de nombreux utilisateurs s'appuient encore sur Babel pour d'autres transformations, donc un passage à Babel était quelque peu inévitable pour eux. Cependant, cela pourrait changer à l'avenir.
Plus important encore, l'implémentation de Webpack dans le même benchmark utilise également SWC.
Code : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | use std::{ fs, path::Path, process::{Child, Command, Stdio}, }; use anyhow::{anyhow, Context, Result}; use regex::Regex; use crate::{ bundlers::Bundler, util::{ npm::{self, NpmPackage}, wait_for_match, }, }; pub struct Webpack; impl Bundler for Webpack { fn get_name(&self) -> &str { "Webpack CSR" } fn prepare(&self, install_dir: &Path) -> Result<()> { npm::install( install_dir, &[ NpmPackage::new("@pmmmwh/react-refresh-webpack-plugin", "0.5.7"), NpmPackage::new("@swc/core", "1.2.249"), NpmPackage::new("react-refresh", "0.14.0"), NpmPackage::new("swc-loader", "0.2.3"), NpmPackage::new("webpack", "5.74.0"), NpmPackage::new("webpack-cli", "4.10.0"), NpmPackage::new("webpack-dev-server", "4.11.0"), ], ) .context("failed to install from npm")?; fs::write( install_dir.join("webpack.config.js"), include_bytes!("webpack.config.js"), )?; Ok(()) } fn start_server(&self, test_dir: &Path) -> Result<(Child, String)> { let mut proc = Command::new("node") .args([ (test_dir .join("node_modules") .join("webpack-dev-server") .join("bin") .join("webpack-dev-server.js") .to_str() .unwrap()), "--port", "0", ]) .env("NO_COLOR", "1") .current_dir(test_dir) .stdout(Stdio::piped()) .stderr(Stdio::piped()) .spawn() .context("failed to run `webpack-dev-server` command")?; let addr = wait_for_match( proc.stderr .as_mut() .ok_or_else(|| anyhow!("missing stderr"))?, Regex::new("\\[webpack\\-dev\\-server\\] Loopback:\\s+(.*)")?, ) .ok_or_else(|| anyhow!("failed to find devserver address"))?; Ok((proc, addr)) } } |
Le noyau de Vite ne repose pas sur Babel. L'utilisation de SWC au lieu de Babel pour gérer les transformations React ne nécessite aucune modification dans Vite lui-même - il suffit de remplacer le plugin React par défaut par vite-plugin-swc-react-refresh. Après le changement, une amélioration significative pour Vite dans le cas de root a été constaté, rattrapant ainsi Next :
Il est intéressant de noter que la courbe de croissance montre que Next/turbo est devenu 4x plus lent dans le cas de la racine par rapport au cas de la feuille, alors que Vite est devenu seulement 2,4x plus lent. Cela implique une courbe où Vite HMR évolue mieux dans des composants encore plus grands.
De plus, le passage au SWC devrait également améliorer les métriques de démarrage à froid de Vite dans les benchmarks de Vercel.
Performances sur différents matériels
Comme il s'agit d'un benchmark mixte qui implique à la fois Node.js et des parties natives de Rust, il y aura une variance non-triviale sur différents matériels. Les chiffres affichés par Evan You ont été recueillis sur un MacBook Pro M1. D'autres utilisateurs ont exécuté le même benchmark sur différents matériels et ont rapporté des résultats différents. Dans certains cas, Vite est plus rapide avec root, alors que dans d'autres, Vite est significativement plus rapide dans les deux cas.
Après la publication du benchmark d’Evan You, Vercel a publié un billet de blog clarifiant leurs méthodologies de benchmark, et a rendu leur benchmark disponible pour une vérification publique. « Turbopack et Next.js 13.0.1 sont sortis, corrigeant une régression qui s'est glissée avant la sortie publique et après que les premiers benchmarks aient été effectués. Nous avons également corrigé un bug d'arrondi incorrect sur notre site Web (0,01s → 15ms). Nous apprécions le travail d'Evan You qui nous a permis d'identifier et de corriger ce problème », écrit Vercel.
You Yuxi, le créateur de Vue.js, estime que la concurrence pour les logiciels libres doit être fondée sur une communication ouverte, une comparaison équitable et un respect mutuel. Il a donc été déçu et inquiet lorsqu'il a vu que Vercel utilisait des données soigneusement sélectionnées, non évaluées par des pairs et trompeuses pour son marketing, un scénario qui ne se produit généralement que dans le cadre d'une compétition commerciale.
Sources : Evan YOU, Turbo
Et vous ?
Quel est votre avis sur le sujet ?
Trouvez-vous pertinent le benchmark réalisé par Evan YOU ?
Voir aussi :
Turbopack, le successeur de Webpack basé sur Rust, conçu pour faciliter le développement d'applications web modernes, peut prendre 1,8 seconde pour démarrer, tandis que Vite prend 11,4 secondes
Next.js 13 est disponible, elle apporte Turbopack, le nouveau successeur de Webpack basé sur Rust, sur une application comportant 3 000 modules, le démarrage de Turbopack prend 1,8 seconde