Leçon 13 / 16

Charger une fonctionnalité à la demande

20 min JavaScript — modularité, performance et API navigateur Gratuit

Objectif : Retarder le chargement du module d’export du résumé jusqu’à la première demande de l’utilisateur.

Un module d’export n’a pas besoin d’être chargé au démarrage si la plupart des utilisations de l’application ne déclenchent jamais cet export. Vous allez différer le chargement de `rapport.js` jusqu’à la demande de résumé, tout en gardant l’application utilisable si ce chargement échoue. L’utilisateur attend ainsi moins de code au démarrage, et le module reste indépendant de l’interface.

Dans la leçon sur les modules ES, vous avez utilisé des imports statiques pour les dépendances nécessaires dès le démarrage. Ici, la fonctionnalité est facultative : un import dynamique, écrit sous la forme `import("./rapport.js")`, renvoie une promesse qui se résout avec le module chargé. Le chemin reste relatif au fichier qui effectue l’import, ici `js/main.js`.

Créer un module de rapport indépendant

Le module `rapport.js` transforme une liste de tâches en texte. Il ne connaît ni le document HTML ni les boutons : il reçoit ses données en argument et retourne une chaîne. Dans cet exemple, chaque tâche comporte les propriétés `libelle` et `terminee`, conformément à la forme utilisée pour les tâches du projet.

JavaScript
// js/rapport.js
export function creerRapport(taches) {
  const terminees = taches.filter((tache) => tache.terminee).length;
  const lignes = [
    "Résumé des tâches",
    `${terminees} tâche(s) terminée(s) sur ${taches.length}`,
    "",
    ...taches.map((tache) => {
      const marque = tache.terminee ? "[x]" : "[ ]";
      return `${marque} ${tache.libelle}`;
    })
  ];

  return lignes.join("\n");
}
Aperçu du rendu
Chargement de l'aperçu…
Résultat attendu
Résumé des tâches
1 tâche(s) terminée(s) sur 2

[x] Préparer le compte rendu
[ ] Envoyer le compte rendu

La fonction ne modifie pas le tableau reçu. Sa sortie est du texte ordinaire, que l’application pourra ensuite transmettre à son mécanisme de copie déjà en place. Le module n’est pas importé statiquement dans `main.js` : il ne sera donc pas demandé au navigateur avant la première utilisation de la fonctionnalité.

Charger le rapport à la demande

Dans `main.js`, appelez une fonction asynchrone depuis le gestionnaire existant de la commande de résumé. Elle importe le module, appelle sa fonction exportée et transmet le texte à la fonction de copie du projet. Le code suivant montre cette séquence sous la forme d’une fonction complète : son paramètre `copierTexte` est l’adaptateur de copie déjà géré par `clipboard.js`.

JavaScript
// À placer dans js/main.js et à appeler à la demande.
export async function exporterRapport(taches, copierTexte) {
  try {
    const moduleRapport = await import("./rapport.js");
    const texte = moduleRapport.creerRapport(taches);
    await copierTexte(texte);
  } catch (erreur) {
    console.error("Le rapport n’a pas pu être chargé ou copié.", erreur);
  }
}
Aperçu du rendu
Chargement de l'aperçu…

Appelez `exporterRapport` depuis l’action utilisateur qui demande le résumé, en lui passant l’état courant et la fonction de copie. Le `await` attend le chargement avant d’utiliser `creerRapport` ; sans cette attente, le code tenterait d’accéder à l’export avant que le module soit disponible. L’exception couvre ici le chargement et l’appel de copie : adaptez le retour utilisateur à la convention déjà utilisée par votre application.

Éviter les demandes répétées

Les navigateurs mettent généralement en cache les modules chargés : un second import du même chemin ne signifie pas nécessairement un second téléchargement. Si vous voulez aussi conserver explicitement la promesse de chargement dans l’application, mémorisez-la après le premier appel. Une promesse rejetée peut être retirée du cache pour autoriser une nouvelle tentative.

JavaScript
let chargementRapport;

export async function exporterRapport(taches, copierTexte) {
  try {
    if (!chargementRapport) {
      chargementRapport = import("./rapport.js");
    }

    const moduleRapport = await chargementRapport;
    await copierTexte(moduleRapport.creerRapport(taches));
  } catch (erreur) {
    chargementRapport = undefined;
    console.error("Le rapport n’a pas pu être chargé ou copié.", erreur);
  }
}
Aperçu du rendu
Chargement de l'aperçu…

Cette variante partage le même chargement si plusieurs demandes surviennent avant sa résolution. Elle remet la variable à `undefined` en cas d’échec afin qu’une demande ultérieure puisse réessayer. Dans une intégration qui distingue les erreurs de copie de celles d’import, limitez cette remise à zéro au seul échec de chargement : une copie refusée ne signifie pas que le module n’a pas été chargé.

À retenir

  • L’import dynamique charge `rapport.js` seulement lorsque la fonctionnalité est demandée.
  • Son résultat est une promesse : attendez-la avant d’utiliser les exports du module.
  • Gardez `rapport.js` centré sur la production du texte ; laissez la copie à l’adaptateur existant.
  • Traitez l’échec de chargement et évitez de déclencher le chargement au démarrage.

Dans la prochaine leçon, vous assemblerez les modules et leurs interfaces dans le point d’entrée de l’application.

Envie d'aller plus loin ?

Les cours Enovatic sont gratuits et le resteront. Si vous cherchez un accompagnement encadré, nos formations professionnelles sont animées par les mêmes formateurs.