Fractionnement du code avec des importations dynamiques dans Next.js

Découvrez comment accélérer votre application Next.js grâce au fractionnement du code et aux stratégies de chargement intelligentes.

Cet article décrit les différents types de répartition du code et explique comment utiliser les importations dynamiques pour accélérer vos applications Next.js.

Répartition du code basée sur les routes et les composants

Par défaut, Next.js divise votre code JavaScript en blocs distincts pour chaque route. Lorsque les utilisateurs chargent votre application, Next.js n'envoie que le code nécessaire pour la route initiale. Lorsque les utilisateurs parcourent l'application, ils récupèrent les fragments associés aux autres routes. La division du code basée sur les routes réduit la quantité de script qui doit être analysée et compilée en une seule fois, ce qui accélère le chargement des pages.

Bien que la division du code basée sur les routes soit une bonne option par défaut, vous pouvez optimiser davantage le processus de chargement avec la division du code au niveau du composant. Si votre application comporte des composants volumineux, il est judicieux de les diviser en morceaux distincts. De cette façon, tous les composants volumineux qui ne sont pas critiques ou qui ne s'affichent que lors de certaines interactions utilisateur (comme cliquer sur un bouton) peuvent être chargés de manière différée.

Next.js est compatible avec les import() dynamiques, ce qui vous permet d'importer des modules JavaScript (y compris des composants React) de manière dynamique et de charger chaque importation en tant que bloc distinct. Vous bénéficiez ainsi d'une division du code au niveau des composants et pouvez contrôler le chargement des ressources afin que les utilisateurs ne téléchargent que le code dont ils ont besoin pour la partie du site qu'ils consultent. Dans Next.js, ces composants sont rendus côté serveur (SSR) par défaut.

Importations dynamiques en action

Cet article inclut plusieurs versions d'une application exemple qui se compose d'une page simple avec un bouton. Lorsque vous cliquez sur le bouton, vous voyez un adorable chiot. À mesure que vous parcourrez chaque version de l'application, vous verrez en quoi les importations dynamiques sont différentes des importations statiques et comment les utiliser.

Dans la première version de l'application, le chiot vit dans components/Puppy.js. Pour afficher le chiot sur la page, l'application importe le composant Puppy dans index.js à l'aide d'une instruction d'importation statique:

import Puppy from "../components/Puppy";

Pour voir comment Next.js regroupe l'application, inspectez la trace réseau dans les outils pour les développeurs:

  1. Pour prévisualiser le site, appuyez sur Afficher l'application, puis sur Plein écran plein écran.

  2. Appuyez sur Ctrl+Maj+J (ou Cmd+Option+J sur Mac) pour ouvrir DevTools.

  3. Cliquez sur l'onglet Réseau.

  4. Cochez la case Disable cache (Désactiver le cache).

  5. Actualisez la page.

Lorsque vous chargez la page, tout le code nécessaire, y compris le composant Puppy.js, est regroupé dans index.js:

Onglet "Réseau" des outils de développement affichant six fichiers JavaScript: index.js, app.js, webpack.js, main.js, 0.js et le fichier DLL (Dynamic Link Library).

Lorsque vous appuyez sur le bouton Click me (Cliquez ici), seule la requête pour le fichier JPEG du chiot est ajoutée à l'onglet Network (Réseau) :

Onglet "Réseau" de DevTools après le clic sur le bouton, affichant les mêmes six fichiers JavaScript et une même image.

L'inconvénient de cette approche est que, même si les utilisateurs ne cliquent pas sur le bouton pour voir le chiot, ils doivent charger le composant Puppy, car il est inclus dans index.js. Dans cet exemple, ce n'est pas un problème, mais dans les applications réelles, il est souvent très utile de ne charger de grands composants que lorsque cela est nécessaire.

Examinez maintenant une deuxième version de l'application, dans laquelle l'importation statique est remplacée par une importation dynamique. Next.js inclut next/dynamic, ce qui permet d'utiliser des importations dynamiques pour tous les composants de Next:

import Puppy from "../components/Puppy";
import dynamic from "next/dynamic";

// ...

const Puppy = dynamic(import("../components/Puppy"));

Suivez les étapes du premier exemple pour inspecter la trace réseau.

Lorsque vous chargez l'application pour la première fois, seul index.js est téléchargé. Cette fois, il est 0,5 ko plus petit (il est passé de 37,9 ko à 37,4 ko), car il n'inclut pas le code du composant Puppy:

DevTools Network affichant les six mêmes fichiers JavaScript, sauf que le fichier index.js est désormais 0,5 Ko plus petit.

Le composant Puppy se trouve désormais dans un bloc distinct, 1.js, qui n'est chargé que lorsque vous appuyez sur le bouton:

Onglet "Réseau" des outils de développement après avoir cliqué sur le bouton, montrant le fichier 1.js supplémentaire et l'image ajoutée en bas de la liste des fichiers.

Dans les applications réelles, les composants sont souvent beaucoup plus volumineux. Leur chargement différé peut entraîner une réduction de plusieurs centaines de kilo-octets de votre charge utile JavaScript initiale.

Importations dynamiques avec un indicateur de chargement personnalisé

Lorsque vous chargez des ressources de manière différée, nous vous recommandons de fournir un indicateur de chargement en cas de retard. Dans Next.js, vous pouvez le faire en fournissant un argument supplémentaire à la fonction dynamic():

const Puppy = dynamic(() => import("../components/Puppy"), {
  loading: () => <p>Loading...</p>
});

Pour voir l'indicateur de chargement en action, simulez une connexion réseau lente dans DevTools:

  1. Pour prévisualiser le site, appuyez sur View App (Afficher l'application), puis sur Fullscreen (Plein écran) plein écran.

  2. Appuyez sur Ctrl+Maj+J (ou Cmd+Option+J sur Mac) pour ouvrir DevTools.

  3. Cliquez sur l'onglet Réseau.

  4. Cochez la case Disable cache (Désactiver le cache).

  5. Dans la liste déroulante Limitation, sélectionnez 3G rapide.

  6. Appuyez sur le bouton Cliquez ici.

Lorsque vous cliquez sur le bouton, le chargement du composant prend un certain temps, et l'application affiche le message "Loading…" (Chargement en cours…) en attendant.

Écran sombre avec du texte

Importations dynamiques sans serveur côté serveur

Si vous devez afficher un composant uniquement côté client (par exemple, un widget de chat), vous pouvez le faire en définissant l'option ssr sur false:

const Puppy = dynamic(() => import("../components/Puppy"), {
  ssr: false,
});

Conclusion

Grâce à la prise en charge des importations dynamiques, Next.js vous permet de diviser le code au niveau des composants, ce qui peut réduire vos charges utiles JavaScript et améliorer le temps de chargement de l'application. Tous les composants sont affichés par défaut côté serveur. Vous pouvez désactiver cette option si nécessaire.