À propos de ce cours
Chapitre 17 — Les modules et l'organisation du code · 17.2 Export par défaut, exports nommés et import dynamique
• utiliser un export par défaut et des exports nommés dans le même module ;
• renommer un import avec
as et regrouper les imports avec import * as; • créer un fichier « baril » qui ré-exporte plusieurs modules ;
• comprendre les liaisons vivantes et charger un module à la demande avec
import(). 
Figure 1 — Les cinq façons de partager du code entre modules.
1. Export par défaut et exports nommés
- Export nommé: autant qu'on veut par fichier ; on les importe entre accolades, avec leur nom exact.
- Export par défaut (
export default) : un seul par fichier, pour la « chose principale » du module (une classe, un composant…). On l'importe sans accolades, avec le nom de son choix.
📄 utilisateur.js
// Export PAR DÉFAUT : la « chose principale » du module (un seul par fichier)
export default class Utilisateur {
constructor(nom, role = "membre") {
this.nom = nom;
this.role = role;
}
presenter() {
return `${this.nom} (${this.role})`;
}
}
// Exports NOMMÉS : des éléments secondaires (autant qu'on veut)
export const ROLES = ["membre", "admin"];
export function estAdmin(utilisateur) {
return utilisateur.role === "admin";
}
📄 outils/texte.js
export const majuscules = (t) => t.toUpperCase();
export const inverser = (t) => [...t].reverse().join("");
📄 outils/nombres.js
export const moyenne = (liste) => liste.reduce((s, x) => s + x, 0) / liste.length;
📄 outils/index.js
// « Fichier baril » : il ré-exporte, pour offrir un seul point d'entrée
export { majuscules, inverser } from "./texte.js";
export { moyenne } from "./nombres.js";
📄 main.js
// Défaut : nom libre, sans accolades. Nommés : entre accolades, nom exact.
import Personne, { ROLES, estAdmin as verifierAdmin } from "./utilisateur.js";
import * as Outils from "./outils/index.js";
const amina = new Personne("Amina", "admin");
console.log(amina.presenter());
console.log("Rôles :", ROLES.join(", "));
console.log("Admin ?", verifierAdmin(amina));
// Espace de noms : tous les exports sous un seul objet
console.log(Outils.majuscules("modules"), Outils.inverser("abc"));
Dans le terminal : node main.js
Amina (admin) Rôles : membre, admin Admin ? true MODULES cba
import Personne, { … }: le défaut (Personne, nom choisi librement) puis les nommés.estAdmin as verifierAdmin: renomme un import, utile en cas de conflit de noms.import * as Outils: tous les exports nommés regroupés dans un objet.outils/index.jsest un fichier baril: il ne contient rien d'autre que des ré-exports et offre un point d'entrée unique pour le dossier.
Beaucoup d'équipes préfèrent n'utiliser que des exports nommés: le nom est le même partout, l'éditeur peut renommer automatiquement et l'auto-complétion fonctionne mieux. L'export par défaut reste courant pour une classe ou un composant unique par fichier.
2. Les imports sont des liaisons vivantes
Un import n'est pas une copie de la valeur : c'est une vue en lecture seule sur la variable du module d'origine.
📄 compteur.js
// Les imports sont des LIAISONS VIVANTES (live bindings), pas des copies
export let total = 0;
export function incrementer() {
total++;
}
📄 live.js
import { total, incrementer } from "./compteur.js";
console.log("Avant :", total);
incrementer();
incrementer();
console.log("Après :", total); // la valeur importée a suivi
try {
total = 100; // interdit : un import est en lecture seule
} catch (e) {
console.log(e.constructor.name + " :", e.message);
}
Dans le terminal : node live.js
Avant : 0 Après : 2 TypeError : Assignment to constant variable.
Le module qui importe voit les changements, mais ne peut pas réassigner la variable. Seul le module propriétaire peut la modifier, ici par la fonction incrementer.
3. L'import dynamique : import()
Les instructions import … from sont statiques: elles s'écrivent en haut du fichier, et tous les modules sont chargés au démarrage.
import("chemin"), avec des parenthèses, est une fonction qui charge un module au moment où elle s'exécute
et renvoie une promesse (voir le chapitre 18).
📄 export-csv.js
console.log("(module export-csv chargé)");
export function versCSV(lignes) {
return lignes.map((l) => l.join(";")).join("\n");
}
📄 dynamique.js
// import() dynamique : charge un module SEULEMENT quand on en a besoin
const notes = [["Amina", 15], ["Sami", 12]];
async function exporter(format) {
if (format === "csv") {
const { versCSV } = await import("./export-csv.js"); // renvoie une promesse
return versCSV(notes);
}
return JSON.stringify(notes);
}
console.log("Démarrage : export-csv.js n'est pas encore chargé");
console.log(await exporter("json"));
console.log(await exporter("csv"));
console.log(await exporter("csv")); // 2e appel : module déjà en cache, pas rechargé
Dans le terminal : node dynamique.js
Démarrage : export-csv.js n'est pas encore chargé [["Amina",15],["Sami",12]] (module export-csv chargé) Amina;15 Sami;12 Amina;15 Sami;12
Le message « module export-csv chargé » n'apparaît qu'au premier export CSV, et une seule fois : un module n'est évalué qu'une fois, puis mis en cache.
await est autorisé directement dans dynamique.js parce que c'est un module (top-level await).
Quand l'utiliser ? Pour une fonctionnalité lourde et rarement utilisée (export PDF, éditeur de texte riche, graphique), pour charger une langue selon l'utilisateur, ou un module différent selon l'appareil.
• Nommés :
export const x → import { x }; défaut : export default → import nomLibre. •
as renomme ; import * as M regroupe ; export { x } from ré-exporte.• Un import est une liaison vivante en lecture seule.
•
import() charge un module à la demande et renvoie une promesse ; un module n'est évalué qu'une fois.🛠 Activité 2 — Une petite bibliothèque d'outils
Mission : Créez un dossier outils/ contenant texte.js, dates.js et index.js, ainsi qu'une classe Etudiant en export par défaut.
Questions pour avancer (répondez dans votre compte rendu, puis appliquez dans votre projet) :
- Dans
texte.js, écrivezcapitaliser,compterMotsetslug(« Bonjour le monde » → « bonjour-le-monde »). Export nommé ou par défaut ? Pourquoi ? - Créez
etudiant.jsqui exporte par défaut une classeEtudiantet, en exports nommés, une constanteNIVEAUX. Écrivez l'import qui récupère les deux en une seule ligne. - Importez la classe sous le nom
Eleve. Est-ce possible ? Et pour un export nommé, que faut-il écrire ? - Écrivez
outils/index.jspour qu'un fichier puisse faireimport { capitaliser, formaterDate } from "./outils/index.js". Quel est l'intérêt si vous déplacez plus tardcapitaliserdans un autre fichier ? - Reproduisez l'exemple du compteur avec un module
score.js. Pourquoi l'auteur du module a-t-il intérêt à ce que les autres ne puissent pas modifierscoredirectement ? - Ajoutez une fonction
exporterPDFdans un module séparé, chargé avecimport()seulement si l'utilisateur tape « pdf ». Ajoutez unconsole.logen haut du module : combien de fois s'affiche-t-il si on exporte trois fois ? - Que renvoie
import("./inexistant.js")? Comment gérez-vous l'erreur ?
Je vérifie / je rends :
- ☐ Le dossier complet et un
main.jsqui démontre chaque forme d'import. - ☐ Les réponses aux questions 3, 5 et 6.
← 17.1 Les fichiers et modules JavaScript (import / export)17.3 Les modules dans le navigateur et dans Node.js →