CommonJS en JavaScript : require, module.exports et l'héritage de Node

CommonJS est l'ancien système de modules de Node : require pour charger, module.exports pour publier. Voici ses règles et sa cohabitation avec les modules ES.
3 min de lecture
Believemy logo

Avant que le langage n'ait ses propres modules, Node avait besoin d'un moyen de découper un programme en fichiers. Il a adopté CommonJS, et des millions de paquets ont été publiés sous cette forme.

Le résultat se voit encore aujourd'hui : la plupart des projets serveur croisent les deux systèmes, et savoir lequel s'applique évite une bonne moitié des messages d'erreur au démarrage.


Définition

CommonJS est un système de modules dans lequel un fichier publie ses valeurs en les posant sur l'objet module.exports, et en récupère d'autres en appelant la fonction require(). Contrairement à un Module ES, tout se joue à l'exécution : require() est un appel de fonction comme un autre.

JAVASCRIPT
// panier.js
const TVA = 0.2;

function totalTTC(ht) {
  return ht * (1 + TVA);
}

module.exports = { TVA, totalTTC };

// facture.js
const { totalTTC } = require('./panier.js');

console.log(totalTTC(100)); // 120

L'extension peut être omise et le chemin sans point désigne un paquet installé, exactement comme avec import.


module.exports et exports, la confusion classique

Au démarrage, exports est un simple raccourci vers module.exports. Poser une clé sur l'un revient donc à la poser sur l'autre, et tout va bien.

Le piège apparaît dès qu'on remplace l'objet entier. module.exports = { b: 2 } coupe le lien : ce qui avait été ajouté à exports auparavant disparaît, et le fichier qui fait le require reçoit uniquement { b: 2 }. La règle est simple : choisissez une des deux écritures et tenez-la sur tout le fichier.

Bon à savoir

require() met chaque module en cache. Le deuxième appel sur le même chemin ne réexécute pas le fichier, il renvoie l'objet déjà construit. C'est ce qui permet de partager un état entre plusieurs fichiers, volontairement ou non.


Ce que CommonJS apporte, et ce qu'il coûte

PointConséquence
Chargement synchroneLe fichier est lu au moment de l'appel, ce qui bloque le reste
Chemin calculé acceptérequire(nomVariable) fonctionne, mais rend l'analyse impossible
Analyse impossibleUn outil ne peut pas savoir ce qui est utilisé, donc pas de Tree shaking (élagage)
Variables fournies__dirname et __filename existent, contrairement aux modules ES


Questions fréquentes

Question

Comment savoir si un fichier est traité en CommonJS ?

Par défaut, un .js est du CommonJS, sauf si le fichier package.json le plus proche déclare "type": "module". L'extension tranche dans tous les cas : .cjs impose CommonJS, .mjs impose les modules ES. En cas de doute, l'extension explicite règle la question définitivement.


Question

Que signifie l'erreur « require is not defined » ?

Elle indique que le fichier est exécuté comme un module ES, où require n'existe pas. Deux issues : convertir le fichier en import, ce qui est préférable sur un projet neuf, ou le renommer en .cjs si le code environnant n'est pas prêt à changer.


Question

CommonJS est-il dépassé ?

Il n'est pas abandonné, et une part énorme des paquets publiés reste écrite ainsi. Pour du code neuf, les modules ES sont le choix par défaut : ce sont ceux du langage, ils fonctionnent aussi dans le navigateur, et ils ouvrent la porte aux optimisations de Bundler (empaqueteur).

Termes connexes

Découvrez notre glossaire JavaScript

Tous les mots de JavaScript expliqués simplement : mots-clés, objets natifs, méthodes, erreurs et concepts. Définitions claires et exemples qui tournent, pour apprendre et pour se dépanner.

Partager cet article

Tu veux nous aider ? Fais un lien vers cet article sur tes réseaux ou encore mieux : sur ton site, dans un article ou dans ta newsletter.