CommonJS vs ECMAScript (ESM)
📘 Comprendre les fichiers .mjs dans Node.js
🧩 1. .mjs, c’est quoi ?
Un fichier .mjs est un module ECMAScript — c’est-à-dire un fichier JavaScript utilisant la syntaxe moderne des imports et exports, comme celle des navigateurs.
// fichier.mjs
import express from "express";
import { maFonction } from "./utils.mjs";
export const app = express();
👉 L’extension .mjs indique à Node.js que le fichier doit être interprété en mode ESM (ECMAScript Module)
et non en CommonJS (le système historique de Node).
⚙️ 2. Contexte historique
Avant 2020, Node.js utilisait uniquement le système CommonJS :
const express = require("express");
module.exports = app;
Mais depuis Node.js 14+, il supporte aussi les modules ECMAScript (mêmes modules que les navigateurs).
Pour éviter toute ambiguïté, Node a introduit une distinction stricte entre :
.js(fichiers interprétés comme CommonJS par défaut).mjs(fichiers interprétés comme modules ECMAScript)
⚙️ 3. Les deux systèmes de modules
| Aspect | CommonJS (.js) |
ESM (.mjs ou type: "module") |
|---|---|---|
| Importation | const X = require("x") |
import X from "x" |
| Exportation | module.exports = X |
export default X |
| Chargement | Synchrone | Asynchrone |
| Scope | Global par fichier | Strict (par module) |
| Compatibilité historique | ✅ Node.js classique | ✅ Node 14+ |
| Syntaxe moderne | ❌ Non | ✅ Oui |
🧠 4. Exemple comparatif
🟠 CommonJS (.js)
// utils.js
const sum = (a, b) => a + b;
module.exports = { sum };
// app.js
const { sum } = require("./utils.js");
console.log(sum(2, 3));
🔵 ECMAScript (.mjs)
// utils.mjs
export function sum(a, b) {
return a + b;
}
// app.mjs
import { sum } from "./utils.mjs";
console.log(sum(2, 3));
🧩 5. Et si je veux rester en .js ?
Tu peux utiliser la syntaxe import/export sans passer en .mjs
en ajoutant ce paramètre dans ton package.json :
{
"type": "module"
}
➡️ Dans ce cas, tous les fichiers .js du projet sont interprétés comme des modules ESM.
Tu n’as donc plus besoin de .mjs.
⚠️ Mais attention :
- Tu ne pourras plus utiliser
require()nimodule.exportsdirectement. - Tu devras tout passer en
import/export.
🧱 6. Quand utiliser .mjs plutôt que .js ?
| Situation | Recommandation |
|---|---|
| Petit projet Node classique (Express, Mongo, etc.) | ✅ Reste en .js (CommonJS) |
| Projet moderne, TypeScript, ou compatible navigateur | ✅ Utilise .mjs ou "type": "module" |
| Tu veux mélanger les deux systèmes | ⚠️ Possible mais à éviter |
| Librairie NPM moderne à publier | ✅ .mjs recommandé pour compatibilité ESM |
🧩 7. Mélanger CommonJS et ESM (cas avancé)
Il est possible de mélanger les deux, mais c’est souvent source de confusion.
Exemple :
main.mjs(ESM) peut importer du CommonJS :import pkg from "./legacy.js";legacy.js(CommonJS) peut importer un ESM avecimport()dynamique :const module = await import("./modern.mjs");
Mais cela complique la maintenance : le mieux est de choisir un seul style.
✅ 8. En résumé
| Élément | .js (CommonJS) |
.mjs (ESM) |
|---|---|---|
| Import | require() |
import |
| Export | module.exports |
export |
| Système | Ancien (Node) | Standard ECMAScript |
| Compatibilité | Universelle | Moderne |
| Recommandé en 2025 | ⚙️ pour rétrocompatibilité | 🟢 pour les projets modernes |
💡 En clair :
.js= modules CommonJS (require,module.exports).mjs= modules ECMAScript (import,export)- Tu peux aussi garder
.jset déclarer"type": "module"dans tonpackage.jsonsi tu veux la syntaxe moderne partout.