1.3Modules : CommonJS (require) vs ES Modules
L'essentiel en 30 secondes
- Un module = un fichier, une responsabilité : on exporte ce qu'on partage, on importe ce dont on a besoin — base de l'organisation.
- CommonJS (historique, omniprésent) : module.exports pour exporter, require() pour importer — synchrone, simple, partout dans npm.
- ES Modules (standard, avenir) : export/import, activés via .mjs ou "type": "module" — recommandé pour un nouveau projet, mais il faut lire les deux.
Mini-cas filé — Salim découpe son application à Alger
L'application de Salim tient en un seul fichier de 500 lignes : les fonctions de calcul mélangées aux lectures de fichiers, impossible à tester. Il découpe en trois modules — calculs, lecture de données, affichage — chacun exportant ses fonctions : d'abord en CommonJS (module.exports/require) pour comprendre, puis il active les ES Modules ("type": "module") pour son nouveau projet. Chaque module a une responsabilité claire et se teste séparément.
Suite du cas 1.1-1.2 — Salim structure son code après le langage et l'asynchrone.
1. CommonJS : module.exports et require()
Aucun programme sérieux ne tient dans un seul fichier : on découpe en modules (fichiers avec une responsabilité, qui s'importent). Le système historique de Node est CommonJS : on exporte avec module.exports (module.exports = { fn1, fn2 }) et on importe avec require() (const truc = require('./monModule')). Synchrone, simple, présent dans des millions de paquets npm. Un module local commence par ./ ou ../ ; un module natif ou npm s'importe par son nom (require('fs')).
Salim crée calculs.js avec module.exports = { additionner, soustraire } et l'importe par require('./calculs') : son fichier de 500 lignes commence à respirer.
2. ES Modules : export et import
Les ES Modules sont la syntaxe standard du langage (la même que dans le navigateur moderne) : on exporte avec export (export function fn() {}) et on importe avec import (import { fn } from './autre.js'). On les active en nommant ses fichiers .mjs ou — plus courant — en ajoutant "type": "module" dans le package.json. ESM est recommandé pour un nouveau projet (standard, avenir, cohérent avec le front-end).
Salim ajoute "type": "module" à son nouveau projet et passe à import { additionner } from './calculs.js' — en notant l'extension .js obligatoire dans le chemin.
3. Comprendre les deux, bien découper
CommonJS reste omniprésent (code existant, tutoriels, paquets) : vous lirez énormément de require/module.exports même en écrivant de l'import/export. Mélanger les deux demande des précautions (importer du CommonJS depuis de l'ESM passe, l'inverse est plus délicat). Au-delà de la syntaxe, l'essentiel est le principe : découper par responsabilité, exporter une interface claire, nommer les fichiers explicitement, éviter les dépendances circulaires.
Salim nomme ses modules calculs.js, donnees.js, affichage.js et n'exporte que le nécessaire : un nouveau développeur sait où chercher sans lui demander.
🔎 Exemple concret — 🔎 Exemple concret — Exporter et importer
D'abord CommonJS, puis ES Modules : deux alternatives, un seul système par fichier.
// --- Alternative A : CommonJS (fichier .js classique) ---
// dans calculs.js :
// module.exports = { additionner, soustraire };
// dans app.js :
const calc = require("./calculs");
console.log(calc.additionner(2, 3));
Lecture : le module local s'importe par son chemin en ./, le paquet ou natif par son nom.
Leçon : en ESM, l'équivalent s'écrit export function additionner + import { additionner } from './calculs.js' — avec l'extension obligatoire.
Vocabulaire de la section
- Module
- Fichier séparé avec une responsabilité, qui exporte ce qu'il rend disponible et importe ce dont il a besoin ; base de l'organisation du code.
Exemple simple : Les calculs.js, donnees.js et affichage.js de Salim.
Ce que ce n'est pas : un fichier unique de 500 lignes qui fait tout.
Réflexe : un fichier = une responsabilité claire.
- CommonJS (CJS)
- Système de modules historique de Node : export avec module.exports, import avec require(). Synchrone, simple, omniprésent dans l'écosystème npm.
Exemple simple : Le require('./calculs') du premier découpage de Salim.
Ce que ce n'est pas : la syntaxe import/export standard du langage.
Réflexe : le lire couramment, même en écrivant de l'ESM.
- ES Modules (ESM)
- Système de modules standard du langage : export avec export, import avec import. Activé via .mjs ou "type":"module" dans package.json.
Exemple simple : Le import { additionner } from './calculs.js' du nouveau projet de Salim.
Ce que ce n'est pas : un require() dans un fichier configuré en ESM.
Réflexe : nouveau projet = ESM, extension explicite.
- require vs import
- Les deux syntaxes d'import : require() (CommonJS) et import (ESM). Les deux coexistent dans le code réel, d'où la nécessité de comprendre les deux.
Exemple simple : Salim lit du require dans les vieux paquets et écrit de l'import dans son projet.
Ce que ce n'est pas : les mélanger dans un même fichier sans configuration adaptée.
Réflexe : un système par fichier, choisi en connaissance de cause.
- Chemin de module
- Local : commence par ./ ou ../ (fichiers du projet). Nom seul : module natif (fs) ou paquet npm de node_modules.
Exemple simple : Le require('./calculs') local vs require('fs') natif chez Salim.
Ce que ce n'est pas : require('calculs') sans ./ pour un fichier du projet (ne sera pas trouvé).
Réflexe : ./ pour le projet, nom seul pour le système et npm.
En pratique — En pratique — Organiser son code en modules
- Créez un module qui exporte des fonctions en CommonJS (module.exports = { fn1, fn2 }) et importez-le avec require('./monModule').
- Recréez le même module en ESM (export function fn1() {}) et importez-le avec import (extension .js explicite).
- Activez ESM dans un projet en ajoutant "type": "module" au package.json, et observez que les .js deviennent des ES Modules.
- Importez un module natif (fs) et un module local (par ./chemin) — repérez la différence de chemin.
Script prêt à dire — proposer le découpage en modules (30 s)
« Ce fichier fait 500 lignes et trois métiers : je propose qu'on le découpe en trois modules — calculs, données, affichage — chacun avec ses exports. On pourra tester chaque partie séparément et les réutiliser ailleurs. »
À dire en revue de code ; montrer le plan des trois modules avant de découper.
Modèle copier-coller — module CommonJS + usage
// calculs.js : on exporte ce qu'on partage
function additionner(a, b) {
return a + b;
}
function soustraire(a, b) {
return a - b;
}
module.exports = { additionner, soustraire };
// app.js : on importe ce dont on a besoin
const calc = require("./calculs");
console.log(calc.additionner(2, 3));
console.log(calc.soustraire(5, 2));
Fichier unique à découper
Repérer les responsabilités (calculs, données, affichage), extraire un module à la fois en vérifiant avec node à chaque étape — comme Salim avec ses 500 lignes.
Nouveau projet à Alger
Salim démarre en ESM ("type": "module") : même syntaxe import/export que le front-end de l'équipe, un seul système à connaître.
Vieux paquets en require
Face à de la documentation en require : savoir la lire et l'utiliser telle quelle, sans convertir tout le projet pour autant.
Nommage d'équipe
Un nom de fichier qui dit ce qu'il fait (donnees.js, validation.js) : la structure devient une documentation gratuite pour le prochain développeur.
✓ Bonnes pratiques
- Un module = une responsabilité.
- N'exporter que le nécessaire.
- Un système par fichier (pas de mélange).
✗ Pièges fréquents
- Mélanger require et import sans config.
- Oublier ./ pour un module local.
- Oublier l'extension en ESM.
Points clés à retenir
- Découper le code en MODULES (fichiers avec une responsabilité, qui s'exportent/importent) = fondamental pour l'organisation et la maintenabilité.
- COMMONJS (historique, omniprésent) : export module.exports, import require(). Synchrone, dans des millions de paquets npm.
- ES MODULES (standard, avenir) : export export, import import ; activés via .mjs ou "type":"module" dans package.json.
- Comprendre les DEUX (require ET import coexistent) ; ESM recommandé pour un nouveau projet. Le PRINCIPE prime sur la syntaxe.
Défi 48h — appliquez demain
Extrayez un module de votre code (modèle ci-dessus) : module.exports + require('./...'), lancez avec node, puis convertissez-le en export/import. 20 minutes suffisent.
- Je peux expliquer module, export et import.
- Je sais distinguer require (CJS) de import (ESM).
- J'ai découpé un module et l'ai importé des deux façons.
Questions fréquentes
CommonJS ou ES Modules : lequel choisir pour mon projet ?
Pour un nouveau projet, ESM est recommandé : c'est le standard officiel du langage (pas une invention de Node), cohérent avec le front-end (même syntaxe dans le navigateur), et la direction d'avenir. Mais CommonJS reste un choix valable (simplicité, compatibilité avec le code existant) — et surtout, vous lirez énormément de CommonJS (paquets, tutoriels, code existant). Pourquoi deux systèmes ? Node a créé CommonJS en 2009 car JavaScript n'avait alors aucun système de modules ; le langage a standardisé les ES Modules en 2015 et Node les a adoptés sans casser l'existant. D'où la coexistence à connaître.
Comment bien organiser mon code en modules, au-delà de la syntaxe ?
C'est une compétence d'architecture indépendante de require/import. Chaque module a une responsabilité claire (utilisateurs, base de données, routes, utilitaires) — pas de fourre-tout. Découpez par fonctionnalité, exportez une interface claire et minimale (le public, le reste reste privé), nommez explicitement (userService.js, validation.js), évitez les dépendances circulaires (A importe B qui importe A) en organisant hiérarchiquement. Comme Salim : trois modules nommés valent mieux qu'un fichier de 500 lignes.
Comment importer un module local en CommonJS ?