Accueil / Articles

Ajuster les nouveaux contrôles de chunking de Turbopack dans Next.js 16.3

Un aperçu pratique de la nouvelle configuration turbopackChunking dans Next.js 16.3, expliquant comment maxChunkCountPerGroup et generateComponentChunks influencent la taille du bundle ainsi que le cache.

6 min de lecture1482 mots

Il était 16h40 un vendredi, précisément au moment où l’on ferme l’ordinateur portable pour le week-end, lorsque un déploiement de routine d’une application de tableau de bord a soudain cessé d’être ordinaire. Une compilation qui prenait normalement 40 secondes a duré un peu plus de trois minutes, et le paquet client pour la route principale a augmenté de près de 300 Ko. Aucune route n’avait été modifiée, et aucune nouvelle dépendance n’avait été ajoutée pour expliquer ce phénomène. La seule modification de la semaine était une légère mise à jour de la version de Next.js. Ce qui a suivi, c’est une soirée passée à fixer l’onglet Réseau, en observant quatre gros fichiers JavaScript se charger les uns après les autres, alors que douze petits fichiers suffisaient auparavant à accomplir la même tâche.

La cause n’était pas une erreur. C’était simplement la logique de segmentation de Turbopack qui fonctionnait exactement comme conçu, mais pas de manière conforme aux attentes.

Pourquoi le problème de segmentation n’a jamais vraiment été résolu

C’est un problème que les outils de bundling tentent de résoudre depuis environ dix ans. Le SplitChunksPlugin de Webpack proposait des paramètres tels que minSize, maxSize et cacheGroups, que presque personne ne comprenait vraiment en profondeur ; ils avaient été pour la plupart copiés d’un thread de Stack Overflow datant de 2019. Le compromis fondamental reste inchangé : regrouper les fichiers en moins de blocs plus gros réduit le nombre de requêtes HTTP, mais nuit au cacheage, car un simple changement dans un fichier CSS peut rendre invalide tout un bundle de 500 Ko. Diviser les fichiers en de nombreux blocs plus petits améliore la granularité du cache, mais augmente le nombre de allers-retours, ce qui devient rapidement perceptible sur une connexion lente.

Turbopack a hérité de cette même nécessité d’équilibre, et jusqu’à récemment il penchait fortement en faveur de la consolidation. C’est un choix raisonnable pour une session à une seule page, où la plupart des ressources sont de toute façon téléchargées une seule fois. Cependant, cela devient un inconvénient si les utilisateurs naviguent fréquemment à l’intérieur d’une application volumineuse, car le code déjà en cache continue d’être téléchargé à nouveau, associé au nouveau code qui se trouve à côté de lui.

Qu’est-ce qui a changé dans 16.3

Avec Next.js 16.3, le comportement de fusion n’est plus caché derrière une seule heuristique opaque ; il est désormais géré directement via la configuration. Un nouveau bloc turbopackChunking a été ajouté, et les deux paramètres les plus importants sont maxChunkCountPerGroup et maxMergeChunkSize.

// next.config.js
module.exports = {
  experimental: {
    turbopackChunking: {
      maxChunkCountPerGroup: 40, // default
      maxMergeChunkSize: 200_000, // bytes, default
    },
  },
};

Une valeur plus basse pour maxChunkCountPerGroup pousse Turbopack vers une fusion plus agressive : moins de requêtes par chargement de page, mais une conservation en cache moins efficace au fil des navigations. Une valeur plus élevée génère des blocs plus petits mais plus nombreux qui restent intacts même lorsque des parties non liées de l’application changent. maxMergeChunkSize fixe une limite à la taille d’un bloc fusionné avant que Turbopack cesse d’y intégrer du code supplémentaire, ce qui est utile lorsque une seule grande dépendance fournisseur a tendance à absorber tout ce qui l’entoure.

Aucun de ces paramètres n’existait auparavant. On se contentait simplement de ce que produisait la logique par défaut et on s’adaptait en conséquence.

L’option de segmentation des composants

Une ajoutation plus notable est generateComponentChunks, qui étend la capacité de segmentation de Turbopack aux composants individuels plutôt que de s’arrêter aux limites des routes.

module.exports = {
  experimental: {
    turbopackChunking: {
      generateComponentChunks: true,
    },
  },
};

En activant cette fonctionnalité, Turbopack génère à la fois les versions fusionnées et non fusionnées des blocs de code, permettant au système d’exécution de choisir à l’heure du chargement quelle version télécharger en fonction de ce que le navigateur a déjà mis en cache. Si un composant partagé a été mis en cache lors d’une visite précédente de la page, le système d’exécution peut demander le bloc non fusionné plus petit au lieu de télécharger un paquet fusionné qui duplique du code déjà présent. Il s’agit d’une approche fondamentalement différente de celle qui consiste à calculer à l’avance la taille idéale des blocs ; c’est le premier cas où un outil de bundling reporte cette décision au moment de la demande plutôt que de la fixer lors de la compilation.

Ce que nous avons réellement observé

generateComponentChunks et a observé ce qui se passait au cours des jours suivants. La charge initiale de la page n’a pratiquement pas changé, diminuant d’environ 2 %. Cependant, les navigations répétées, qui représentent l’essentiel de l’utilisation réelle d’une application comme un tableau de bord, ont entraîné une baisse moyenne de la quantité de JS transféré par navigation d’environ 35 %. Telle est l’essence de cette solution : il ne s’agit pas d’une fonctionnalité visant à alléger la première charge, mais plutôt adaptée aux utilisateurs qui naviguent dans l’application pendant dix minutes consécutives. La plupart des benchmarks concernant la taille des fichiers distribués en ligne mesurent un scénario complètement différent, qui ne reflète pas la manière dont les applications avec de nombreuses navigations internes sont réellement utilisées.

La même équipe a également réexaminé la valeur de maxChunkCountPerGroup pour un site de marketing hébergé dans le même monorepo, la réduisant de 40 à 24. Ce site présente principalement des sessions une seule page, de sorte que les demandes réseau supplémentaires générées par un découpage plus fin n’avaient qu’un impact négligeable sans aucun avantage concret. Même outil de base, ajustements opposés, et les deux choix se sont avérés appropriés pour leur contexte respectif. C’est là, sans doute, la véritable leçon : il n’a jamais existé de stratégie de découpage universellement optimale ; Turbopack se contentait simplement de prendre cette décision à votre place sans vous demander votre avis.

Comparaison avec les anciens paramètres de Webpack

Pour ceux qui ont passé des années à se débattre avec splitChunks.cacheGroups, l’équivalent le plus proche dans ce nouveau système est maxMergeChunkSize. Contrairement à de nombreux noms utilisés par Webpack, celui-ci fonctionne exactement comme on pourrait s’y attendre. La configuration de Webpack offrait une douzaine de paramètres peu documentés qui interagissaient entre eux d’une manière que personne n’avait pleinement comprise, et de nombreuses équipes se retrouvaient avec un fichier de configuration hérité d’ingénieurs partis depuis longtemps, que personne n’osait modifier. L’approche de Turbopack est délibérément plus restreinte : on dispose de deux ou trois paramètres au lieu d’une douzaine, ce qui sacrifie une certaine flexibilité face à des cas extrêmes vraiment inhabituels, mais cela réduit également le temps écoulé entre le moment où l’on s’aperçoit que « notre bundle ne semble pas normal » et celui où l’on sait précisément quel chiffre ajuster. Ce compromis est raisonnable à accepter, surtout pour ceux qui préfèrent éviter de…

Il n’y aura plus jamais de configuration cacheGroups pluriannuelle de ce type.

Il existe une autre distinction qui mérite d’être soulignée séparément. Webpack vous obligeait dans une large mesure à réfléchir au découpage en chunks au moment de la compilation, en examinant attentivement les résultats de stats.json pour essayer de prédire ce que le cache du navigateur d’un visiteur réel contiendrait réellement. Le découpage au niveau des composants de Turbopack déplace une partie de cette réflexion au moment de la requête, permettant à l’exécution de vérifier l’état réel du cache au lieu de deviner à l’avance. Il s’agit d’un véritable changement architectural, et non simplement d’un nom différent pour un paramètre de configuration.

L’inconvénient

Cette fonctionnalité est toujours qualifiée d’expérimentale, et la documentation le précise clairement. Une équipe a rencontré un cas où une bibliothèque de visualisation importée dynamiquement s’est divisée d’une manière qui a provoqué temporairement une erreur « échec du chargement du chunk » en production lors d’un déploiement, ce problème familier de référence à un chunk obsolète qui a affecté pratiquement tous les outils de bundling prenant en charge le code-splitting. Un rechargement forcé a résolu le problème pour les utilisateurs concernés, mais cela sert de rappel utile que la segmentation en chunks plus fines élargit plutôt que de réduire les risques liés à ce mode de défaillance particulier.

Il y a aussi la question de l’ajustement de ces paramètres sans données de trafic réelles, ce qui relève essentiellement du hasard. Il vaut la peine de résister à l’envie de modifier les paramètres par défaut dans un projet nouveau tant que vous n’avez pas d’analyses de navigation montrant si vos visiteurs ont tendance à quitter immédiatement ou s’ils naviguent entre une douzaine de routes ou plus au cours d’une seule session. Si ces données n’existent pas encore, c’est une raison tout à fait valable de commencer à les collecter avant d’ajuster toute configuration de segmentation. Ajuster à l’aveugle comporte un risque réel d’obtenir un taux de réussite du cache inférieur à celui que les paramètres par défaut auraient permis, et ce type de dégradation se produit silencieusement. Personne ne soumet un rapport de bug intitulé « La navigation semblait un peu plus lente », ils cessent simplement de revenir.

Vaut-il donc la peine de l’activer ?

Pour le scénario du tableau de bord, la réponse était oui, et la configuration est restée activée. Pour le site de marketing, un seul chiffre a été ajusté et c’était tout. Rien de tout cela ne répare une application fondamentalement défectueuse, et si votre ensemble logiciel est encombré à cause d’une dépendance dont vous n’aviez pas vraiment besoin, aucune stratégie de segmentation au monde ne pourra corriger cette erreur. Ce que cette fonctionnalité offre, c’est une correction ciblée d’un problème précis, ce qui constitue un changement bienvenu par rapport à de nombreuses fonctionnalités d’outils de construction disponibles cette année, un jugement qui pèse lourd pour quiconque a passé plus de soirées qu’il ne le souhaiterait à traquer ce type de bug.

Lectures complémentaires