TW3 — Technologies du Web 3

Runtime Node.js et système de modules

L'event loop, l'objet process, et le système de modules CommonJS/ESM typés avec TypeScript.

Prérequis TypeScript : ce chapitre suppose que vous avez suivi la séance 3 (TypeScript). Les exemples utilisent des types, des interfaces et des imports ESM.

🧠 Qu'est-ce que Node.js

Node.js n'est pas un framework. C'est un runtime JavaScript — un environnement qui exécute du JavaScript (ou du TypeScript transpilé) en dehors du navigateur, avec accès aux API système : fichiers, réseau, processus, mémoire.

// Node.js expose des API système absentes du navigateur
import { stdout } from "node:process"

stdout.write("Bonjour depuis Node.js\n")

Le moteur V8 de Chrome est au cœur de Node.js. Node.js y a ajouté les API système pour en faire un runtime serveur.

Runtime ≠ Framework

  • Un runtime exécute le code (Node.js, Deno, Bun).
  • Un framework structure l'application (Express, Nest, Fastify).
  • Node.js est le runtime — Express est un framework qui s'exécute dessus.

🔄 L'event loop — architecture non-bloquante

Node.js est single-threaded mais non-bloquant. Une seule thread exécute le code JavaScript, mais les I/O (fichier, réseau, base de données) sont déléguées à des mécanismes asynchrones.

import { readFile } from "node:fs/promises"

// Cette ligne ne bloque PAS le thread
const data = await readFile("fichier.txt", "utf8")
console.log(data) // exécuté quand le fichier est lu, plus tard

L'event loop tourne en boucle en 6 phases :

PhaseCe qui s'y passe
timerssetTimeout, setInterval (appels à échéance)
pending callbacksCallbacks I/O système en attente
idle, prepareInterne
pollRécupération des I/O prêts à traiter
checksetImmediate()
close callbackssocket.on('close')
import { setTimeout, setImmediate } from "node:timers"

setTimeout(() => {
  console.log("setTimeout — phase timers")
}, 0)

setImmediate(() => {
  console.log("setImmediate — phase check")
})
// L'ordre d'exécution dépend du contexte (main script vs callback I/O)

Une idée reçue

Node.js n'est pas "plus rapide" que les autres runtimes. Il excelle sur les charges I/O-bound (beaucoup de connexions, peu de calcul CPU). Pour du CPU intensif, il faut du clustering ou déporter la charge.

📦 L'objet process

process est un objet global qui donne accès à l'environnement d'exécution.

import { env, argv, cwd } from "node:process"

// Variables d'environnement (string | undefined)
const port = Number(env.PORT ?? 3000)
const nodeEnv = env.NODE_ENV ?? "development"

// Arguments CLI — argv[0] = "node", argv[1] = chemin du script
const args = argv.slice(2) // ["--port", "8080"]

// Dossier courant d'exécution
const currentDir = cwd()

TypeScript (avec @types/node) donne un type précis à process :

// Sans @types/node, process est any
// Avec @types/node, chaque propriété est typée
interface ProcessEnv {
  PORT?: string
  NODE_ENV?: "development" | "production"
}

declare global {
  namespace NodeJS {
    interface Process {
      env: ProcessEnv
    }
  }
}

📜 Le système de modules — CommonJS vs ESM

Node.js organise le code en modules. Deux systèmes coexistent.

CommonJS (historique)

C'est le système par défaut des fichiers .js dans Node.js. Chaque fichier est un module isolé — il n'y a pas de mot-clé import / export : on utilise module.exports pour exposer et require() pour importer.

// math.js — export CommonJS
const PI = 3.14159

function circonférence(rayon) {
  return 2 * PI * rayon
}

module.exports = { circonférence }
// index.js — import CommonJS
const { circonférence } = require("./math")

console.log(circonférence(10)) // 62.8318

Caractéristiques de CommonJS :

  • module.exports pour exporter, require() pour importer
  • Import synchrone (bloquant) — les dépendances sont chargées avant l'exécution
  • Supporté nativement, aucune configuration requise
  • Limitation : pas de chargement conditionnel, pas de tree-shaking, pas de notation import { x }

ES Modules (standard moderne)

Les ES Modules (ESM) sont le standard JavaScript. Dans Node.js, ils s'activent avec :

  • Extension .mjs, ou
  • "type": "module" dans package.json
// math.mjs — export ESM
export const PI = 3.14159

export function circonférence(rayon) {
  return 2 * PI * rayon
}
// index.mjs — import ESM
import { circonférence, PI } from "./math.mjs"

console.log(circonférence(10))

Règle d'import ESM

Dans les fichiers .ts avec moduleResolution: "NodeNext", l'extension .js est obligatoire dans les chemins d'import, même pour des fichiers .ts ou .mts. Le loader TypeScript résout le fichier source.

// ❌ Incorrect — extension manquante
import { circonférence } from "./math"

// ✅ Correct
import { circonférence } from "./math.js"

📋 Récapitulatif

AspectCommonJSES Modules
Extension.js (ou .cjs).mjs / .js avec "type": "module"
Exportmodule.exports / exportexport
Importrequire()import
OrdreSynchrone, bloquantAsynchrone (dans le navigateur), statique
TypeScriptmodule: "CommonJS"module: "NodeNext"

Quiz du chapitre

3 questions
0 / 3 répondue0%
  1. 1Node.js est :
  2. 2L'event loop de Node.js permet :
  3. 3Dans TypeScript avec moduleResolution NodeNext, comment importer un fichier `.ts` voisin ?
Répondez à toutes les questions pour valider.

Node.js

Terminez le quiz du chapitre pour le marquer comme complété.

Tableau de bord

On this page