1.3 · Modules : CommonJS (require) vs ES Modules

Niveau 1 · JavaScript & bases Node

1.3Modules : CommonJS (require) vs ES Modules

Objectif : découper votre code en modules et maîtriser les deux systèmes (CommonJS require/module.exports et ESM import/export), en comprenant le principe commun.
Temps estimé : 11 min · lecture autonome · Si vous n'avez que 5 min : lisez « L'essentiel en 30s » + le schéma.

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.

Erreur d'interprétation fréquente : « require et import sont interchangeables dans le même fichier » ou « il suffit de renommer en .mjs sans rien changer ». Non. Chaque fichier suit UN système selon la configuration (".type": "module" ou non) : mélanger les syntaxes sans l'expliquer casse l'exécution. Et passer à ESM impose des ajustements (extensions explicites dans les chemins, __dirname absent en ESM pur) — ce n'est pas un simple renommage.
Deux systèmes de modules Même principe, syntaxe différente CommonJS module.exports /require() — historiqueES Modules export / import —standard du langagePrincipe commun Découper,exporter, importer
Même principe, syntaxe différente
Version texte du schéma (SEO / lecteurs d'écran / traduction) : 1) Découper : Salim sort les calculs, les lectures et l'affichage de son fichier unique en trois modules à responsabilité claire. 2) Exporter/importer : en CommonJS via module.exports/require('./calculs'), en ESM via export/import avec extension explicite. 3) Choisir : ESM ("type": "module") pour le projet neuf, lecture courante du CommonJS existant — sans mélanger les deux syntaxes dans un même fichier. Leçon : le principe (découper, exporter, importer) prime sur la syntaxe.

🔎 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

  1. Créez un module qui exporte des fonctions en CommonJS (module.exports = { fn1, fn2 }) et importez-le avec require('./monModule').
  2. Recréez le même module en ESM (export function fn1() {}) et importez-le avec import (extension .js explicite).
  3. Activez ESM dans un projet en ajoutant "type": "module" au package.json, et observez que les .js deviennent des ES Modules.
  4. Importez un module natif (fs) et un module local (par ./chemin) — repérez la différence de chemin.
Vous découpez votre code en modules et maîtrisez les deux systèmes (CommonJS require/module.exports et ESM import/export), en comprenant le principe commun d'organisation.

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.

Checklist sortie de section
  • 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.
Auto-évaluation 1-5 : mes fichiers ont-ils chacun une responsabilité claire ?est-ce que je sais activer ESM et lire du CommonJS ?

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.

Vérifiez votre compréhension

Comment importer un module local en CommonJS ?

Ressources supplémentaires (optionnel, pour aller plus loin)

Examen du niveau 1Questions inédites et durcies pour valider vos acquis