1. CommonJS vs ES Modules

Node.js supporte deux systèmes de modules : CommonJS (CJS), le système historique, et ES Modules (ESM), le standard moderne du JavaScript. Comprendre leurs différences est essentiel pour choisir le bon système dans vos projets.

CommonJS (CJS) — Le système historique

// math-cjs.js — CommonJS
function additionner(a, b) { return a + b; }
const PI = 3.14159;

module.exports = { additionner, PI };

// Dans un autre fichier :
const { additionner, PI } = require('./math-cjs');
console.log(additionner(2, 3)); // 5

ES Modules (ESM) — Le standard moderne

// math-esm.mjs — ES Modules (extension .mjs)
// OU avec "type": "module" dans package.json → .js fonctionne aussi

export function additionner(a, b) { return a + b; }
export const PI = 3.14159;
export default function soustraire(a, b) { return a - b; }

// Dans un autre fichier :
import { additionner, PI } from './math-esm.mjs';
import soustraire from './math-esm.mjs';
console.log(additionner(2, 3)); // 5

// Top-level await possible avec ESM !
const data = await fetch('https://api.example.com/data').then(r => r.json());

Comparatif CJS vs ESM

CritèreCommonJS (CJS)ES Modules (ESM)
Importrequire()import
Exportmodule.exportsexport / export default
ChargementSynchroneAsynchrone (statique)
Extension.js (par défaut).mjs ou "type":"module"
Top-level awaitNonOui
Tree-shakingNonOui
Browser natifNonOui
Usage Node.jsProjets existants, scriptsNouveaux projets recommandé

Activer ESM dans package.json

{
  "name": "mon-projet",
  "version": "1.0.0",
  "type": "module"
}
// Avec "type": "module", tous les fichiers .js sont traités comme ESM
// Les fichiers .cjs restent CommonJS
💡 Recommandation : Pour les nouveaux projets Node.js, préférez ESM. Pour les projets existants ou les scripts rapides, CJS reste parfaitement valide.

2. Modules natifs essentiels

Node.js embarque de nombreux modules natifs. Pas besoin de npm pour ces fonctionnalités de base. Voici les plus importants à connaître.

fs — Système de fichiers

const fs = require('fs');

// Lire un fichier (synchrone pour les scripts)
const contenu = fs.readFileSync('config.json', 'utf8');
const config = JSON.parse(contenu);

// Écrire (asynchrone avec callback)
fs.writeFile('output.txt', 'Hello !', (err) => {
  if (err) throw err;
  console.log('Fichier écrit !');
});

path — Manipulation de chemins

const path = require('path');

// Joindre des segments de chemin (cross-platform !)
const fichier = path.join(__dirname, 'data', 'users.json');
// Windows : C:\projet\data\users.json
// Linux   : /projet/data/users.json

console.log(path.basename('/home/user/photo.jpg'));  // 'photo.jpg'
console.log(path.extname('index.html'));              // '.html'
console.log(path.dirname('/home/user/photo.jpg'));    // '/home/user'
console.log(path.resolve('config.json'));             // Chemin absolu depuis CWD

os — Informations système

const os = require('os');

console.log('OS         :', os.type());          // 'Linux', 'Windows_NT', 'Darwin'
console.log('Platform   :', os.platform());      // 'linux', 'win32', 'darwin'
console.log('Hostname   :', os.hostname());       // Nom de la machine
console.log('CPU(s)     :', os.cpus().length);   // Nombre de coeurs
console.log('RAM totale :', (os.totalmem() / 1073741824).toFixed(1) + ' Go');
console.log('RAM libre  :', (os.freemem()  / 1073741824).toFixed(1) + ' Go');
console.log('Dossier home :', os.homedir());     // /home/user ou C:\Users\user

crypto — Hachage et sécurité

const crypto = require('crypto');

// Hash SHA-256
const hash = crypto.createHash('sha256')
  .update('mon texte secret')
  .digest('hex');
console.log('SHA-256 :', hash);

// UUID aléatoire (Node.js >= 14.17)
const uuid = crypto.randomUUID();
console.log('UUID :', uuid); // ex: '9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d'

// Octets aléatoires (pour tokens)
const token = crypto.randomBytes(32).toString('hex');
console.log('Token :', token);

events — EventEmitter

const EventEmitter = require('events');

// Créer un émetteur personnalisé
class MonEmetteur extends EventEmitter {}
const emetteur = new MonEmetteur();

// Écouter des événements
emetteur.on('data', (payload) => {
  console.log('Données reçues :', payload);
});
emetteur.once('connect', () => {
  console.log('Connecté ! (une seule fois)');
});

// Émettre des événements
emetteur.emit('connect');
emetteur.emit('data', { user: 'Alice', timestamp: Date.now() });
emetteur.emit('data', { user: 'Bob',   timestamp: Date.now() });

3. npm — Gestion des packages

npm est le gestionnaire de packages officiel de Node.js avec plus de 2 millions de packages. Voici les commandes essentielles à maîtriser.

Installer et désinstaller

# Installer une dépendance de production
npm install express
npm i express           # Raccourci

# Installer plusieurs packages
npm install express dotenv cors

# Dépendance de développement uniquement
npm install --save-dev nodemon
npm i -D nodemon        # Raccourci

# Installer une version précise
npm install express@4.18.2

# Désinstaller
npm uninstall express
npm un express          # Raccourci

Lister et mettre à jour

# Lister les packages installés
npm list
npm list --depth=0      # Sans les sous-dépendances

# Voir les packages obsolètes
npm outdated

# Mettre à jour
npm update              # Selon les ranges semver
npm update express      # Package spécifique

# Voir les infos d'un package
npm info dayjs
npm info dayjs version  # Dernière version seulement

Sécurité et audit

# Vérifier les vulnérabilités
npm audit

# Corriger automatiquement
npm audit fix
npm audit fix --force   # ⚠️  Peut casser des APIs

npx — Exécuter sans installer

# Exécuter un package sans l'installer globalement
npx create-react-app mon-app
npx eslint src/
npx prettier --write src/

# Exécuter une version spécifique
npx node@18 --version

# Liste des packages globaux installés
npm list -g --depth=0

Exemple : utiliser dayjs

// Après : npm install dayjs
const dayjs = require('dayjs');
require('dayjs/locale/fr');
dayjs.locale('fr');

const maintenant = dayjs();
console.log(maintenant.format('dddd D MMMM YYYY'));  // vendredi 15 novembre 2024
console.log(maintenant.add(7, 'day').format('DD/MM/YYYY'));  // Dans 7 jours
console.log(dayjs('2024-01-01').fromNow());          // Il y a X mois

4. package.json en détail

Le fichier package.json est le manifeste de votre projet Node.js. Il décrit le projet, ses dépendances et ses scripts.

Champs principaux

{
  "name": "mon-api-node",          // Identifiant unique (lowercase, tirets)
  "version": "1.2.3",             // SemVer obligatoire
  "description": "API REST Node", // Description courte
  "main": "src/index.js",         // Point d'entrée du module
  "type": "module",               // "module" pour ESM, omis pour CJS

  "scripts": {
    "start":  "node src/index.js",         // npm start
    "dev":    "nodemon src/index.js",      // npm run dev
    "test":   "node tests/run.js",         // npm test
    "lint":   "eslint src/",               // npm run lint
    "build":  "node scripts/build.js"      // npm run build
  },

  "dependencies": {
    "express": "^4.18.2",         // Prod : nécessaire au runtime
    "dotenv":  "^16.3.1"
  },
  "devDependencies": {
    "nodemon": "^3.0.2",          // Dev : uniquement en développement
    "eslint":  "^8.56.0"
  },

  "engines": {
    "node": ">=18.0.0",           // Version Node.js minimale requise
    "npm":  ">=9.0.0"
  },

  "private": true,                // Empêche la publication sur npm
  "license": "MIT",
  "author": "Alaa EL HUSSEIN "
}

dependencies vs devDependencies

TypeQuand utiliserExempleInstallé en prod ?
dependenciesNécessaire au runtimeexpress, dotenv, mongooseOui
devDependenciesBuild, tests, outils devnodemon, eslint, jestNon (avec --production)
💡 En production, installez avec npm install --production ou NODE_ENV=production npm install pour n'installer que les dependencies et économiser de l'espace.

5. Semantic Versioning (SemVer)

Le versionnage sémantique définit comment les numéros de version communiquent l'impact des changements. Comprendre SemVer est indispensable pour gérer les dépendances de façon sûre.

Structure d'une version

    1   .   2   .   3
    ↑       ↑       ↑
MAJEURE   MINEURE   PATCH

MAJEURE : Changement incompatible (breaking change)
MINEURE : Nouvelle fonctionnalité, rétrocompatible
PATCH   : Correction de bug, rétrocompatible

Opérateurs de range

NotationRange acceptéeExemple concretUtilisation
1.2.3Exactement 1.2.3Uniquement 1.2.3Reproductibilité totale
^1.2.3>=1.2.3 <2.0.01.2.3 à 1.x.xPar défaut npm — sûr
~1.2.3>=1.2.3 <1.3.01.2.3 à 1.2.xConservateur
*Toute versionDernière stable⚠️ Risqué
>=1.0.01.0.0 et plusToutes >= 1.0.0Rare
1.2.x>=1.2.0 <1.3.0Équivalent à ~1.2.0Explicit

package-lock.json — Verrouillage des versions

# package.json dit : "express": "^4.18.2"
# → npm peut installer 4.19.0, 4.20.1, etc.

# package-lock.json dit : express@4.18.2 exactement
# → npm install réinstalle EXACTEMENT la même version

# Toujours committer package-lock.json !
# Ne pas modifier package-lock.json manuellement.

# Régénérer le lock (après conflit git par ex.) :
rm package-lock.json
npm install

Versions pre-release et tags

# Installer une version pre-release
npm install express@next
npm install react@canary

# Publier avec un tag (pour les auteurs de packages)
npm publish --tag beta    # Version beta
npm publish --tag latest  # Production (défaut)
⚠️ Bonne pratique : Après chaque npm install, vérifiez ce qui a changé avec npm outdated. Mettez à jour régulièrement et testez après chaque mise à jour majeure.
← N01 Intro Node.js Exercices →