4.3 — Gestion de paquets et environnements
🎯 Objectif : comprendre ce qui se passe quand tu fais
npm install, gérer les conflits de versions, et savoir choisir entre npm, pnpm et yarn.
À l'issue de cet axe, tu sauras :
- Lire et comprendre semver (^, ~, exacte)
- Distinguer dependencies, devDependencies, peerDependencies
- Expliquer le rôle du lockfile et savoir quand le commit / le supprimer
- Choisir entre npm, pnpm, yarn classique, yarn berry
- Mettre en place un monorepo avec workspaces
Débutant
Anatomie d’un package.json
Section intitulée « Anatomie d’un package.json »{ "name": "mon-app", "version": "1.4.2", "type": "module", "scripts": { "dev": "vite", "build": "vite build", "test": "vitest", "lint": "eslint ." }, "dependencies": { "react": "^19.0.0", "zod": "~4.3.6" }, "devDependencies": { "vite": "^5.4.0", "vitest": "^2.1.0", "typescript": "^5.7.0" }, "peerDependencies": { "react": "^19.0.0" }, "engines": { "node": ">=20" }}Les 3 types de dépendances
Section intitulée « Les 3 types de dépendances »| Type | Quand utiliser |
|---|---|
dependencies | Code qui tourne en production (React, Express, lodash…) |
devDependencies | Outils de dev (Vite, ESLint, Vitest, TypeScript…) |
peerDependencies | « Mon paquet a besoin de ce paquet, mais tu dois l’installer toi-même » (libs/plugins) |
Erreur classique : mettre TypeScript en dependencies. Il sert à compiler avant le déploiement, donc c’est devDependencies.
Semver — versionning sémantique
Section intitulée « Semver — versionning sémantique »Format : MAJOR.MINOR.PATCH (ex. 2.4.7).
| Niveau | Quand l’incrémenter |
|---|---|
MAJOR (2 → 3) | Changement incompatible (breaking change) |
MINOR (2.4 → 2.5) | Nouvelle fonctionnalité, compatible |
PATCH (2.4.7 → 2.4.8) | Correction de bug, compatible |
Les opérateurs de plage
Section intitulée « Les opérateurs de plage »| Spécificateur | Signifie | Exemple |
|---|---|---|
19.0.0 | Exactement cette version | Pin strict |
^19.0.0 | >= 19.0.0 < 20.0.0 (compatible majeure) | Défaut npm |
~19.0.0 | >= 19.0.0 < 19.1.0 (compatible mineure) | Plus prudent |
* ou latest | N’importe quoi | À éviter |
>= 19.0.0 | Au moins cette version | Pour les peer deps |
Pré-releases
Section intitulée « Pré-releases »"version": "2.0.0-beta.3""version": "5.0.0-rc.1""version": "1.5.0-alpha.7"Le caret n’inclut pas les pré-releases automatiquement : ^2.0.0 ne prendra pas 2.0.0-beta.3.
Le lockfile — la cohérence inter-machines
Section intitulée « Le lockfile — la cohérence inter-machines »Quand tu fais npm install zod, npm ajoute ^4.3.6 au package.json. Mais quel sera exactement le numéro installé chez ton collègue dans 3 mois ?
Le lockfile (package-lock.json, pnpm-lock.yaml, yarn.lock) fige les versions exactes de tout l’arbre de dépendances :
{ "node_modules/zod": { "version": "4.3.6", "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", "integrity": "sha512-..." } // + toutes les transitives}Règle absolue : commit ton lockfile. Sinon ton équipe et ton CI installent des versions différentes, et tu chasses des bugs fantômes.
npm install vs npm ci
Section intitulée « npm install vs npm ci »| Commande | Comportement |
|---|---|
npm install | Met à jour le lockfile si différent du package.json |
npm ci | Installe exactement ce qui est dans le lockfile, jamais ne le modifie |
En CI/CD : toujours npm ci. En local pour ajouter une dep : npm install.
npm vs pnpm vs yarn
Section intitulée « npm vs pnpm vs yarn »| npm | pnpm | yarn classic | yarn berry (v4+) | |
|---|---|---|---|---|
| Vitesse install | 🟡 | 🟢🟢🟢 | 🟢 | 🟢🟢 |
| Espace disque (node_modules) | 🔴 dupliqué | 🟢 lien dur | 🔴 dupliqué | 🟢 PnP |
| Lockfile | package-lock.json | pnpm-lock.yaml | yarn.lock | yarn.lock |
| Workspaces | ✅ | ✅ excellent | ✅ | ✅ |
| Compatibilité écosystème | 🟢 totale | 🟢 totale | 🟢 totale | 🟡 PnP peut casser certains outils |
| Maturité 2026 | 🟢 | 🟢 | 🟢 | 🟢 |
Recommandation 2026 :
- pnpm : meilleur défaut moderne. Rapide, économe en disque, bonne gestion des monorepos.
- npm : si tu veux le strict minimum officiel et zéro outil supplémentaire.
- yarn berry : si l’équipe le maîtrise — l’écosystème PnP peut surprendre.
# Installer pnpmnpm install -g pnpm
# Migrer un projet npm → pnpmrm -rf node_modules package-lock.jsonpnpm installNode.js 24 et TypeScript natif
Section intitulée « Node.js 24 et TypeScript natif »Depuis Node.js 24 (LTS depuis octobre 2025, courant en 2026), une nouveauté change la donne pour les projets TypeScript : le type stripping natif.
# Avec Node 24+node hello.ts # ça marche directement, sans tsx ni ts-nodeSous le capot, Node fait du type stripping : il enlève types, interfaces et autres constructions TS, et exécute le JS résultant. C’est activé par défaut pour les .ts (auparavant via --experimental-strip-types).
Ce que ça apporte :
- Plus besoin de
tsx/ts-nodepour les scripts simples et les outils maison. - Démarrage plus rapide qu’un transpileur en watch.
- TypeScript devient une « surcouche zéro-coût » à l’exécution.
Limites importantes :
- Pas de type-checking au runtime (Node strip les types, ne les valide pas) → garde
tsc --noEmitouastro checken CI. - Subset autorisé : pour un strip purement syntaxique, certaines constructions TS sont interdites (enum traditionnels, namespaces, casts spécifiques). TypeScript 5.8 a introduit l’option
--erasableSyntaxOnlyqui te dit d’avance si ton code est compatible. - En production, on recommande toujours un build TS avec optimisations (sourcemaps, tree-shaking, target précis).
// tsconfig.json — pour vérifier la compatibilité Node-strip{ "compilerOptions": { "erasableSyntaxOnly": true, "verbatimModuleSyntax": true, "target": "ES2023" }}Gérer plusieurs versions de Node.js
Section intitulée « Gérer plusieurs versions de Node.js »Tu travailleras sur des projets en Node 20, 22, 24… Solution : un gestionnaire de versions.
nvm (Linux/Mac/WSL)
Section intitulée « nvm (Linux/Mac/WSL) »curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/master/install.sh | bash
nvm install 24 # installer Node 24 (LTS courant)nvm install 22 # installer Node 22 aussinvm use 24 # basculernvm alias default 22 # version par défautnvm-windows (Windows pur, hors WSL)
Section intitulée « nvm-windows (Windows pur, hors WSL) »Différent projet : github.com/coreybutler/nvm-windows
fnm — la version moderne et rapide
Section intitulée « fnm — la version moderne et rapide »# Installercurl -fsSL https://fnm.vercel.app/install | bash# ou : winget install Schniz.fnm
fnm install 22fnm use 22.nvmrc ou .node-version
Section intitulée « .nvmrc ou .node-version »Fichier à la racine du projet qui dit quelle version utiliser :
22.10.0nvm use le lit automatiquement. Les CI le respectent aussi (GitHub Actions a actions/setup-node qui le détecte).
Scripts npm
Section intitulée « Scripts npm »Les scripts sont des commandes shell exécutables via npm run (ou pnpm/yarn).
{ "scripts": { "dev": "vite", "build": "tsc && vite build", "test": "vitest", "test:watch": "vitest --watch", "lint": "eslint .", "lint:fix": "eslint . --fix", "typecheck": "tsc --noEmit", "ci": "pnpm lint && pnpm typecheck && pnpm test && pnpm build" }}Hooks pré/post
Section intitulée « Hooks pré/post »{ "scripts": { "prebuild": "pnpm typecheck", "build": "vite build", "postbuild": "pnpm test:e2e" }}pnpm build exécute alors prebuild → build → postbuild automatiquement.
Passer des arguments
Section intitulée « Passer des arguments »npm run test -- --watch # double tiret = arguments au scriptpnpm test --watch # pnpm n'a pas besoin du double tiretMonorepos avec workspaces
Section intitulée « Monorepos avec workspaces »Plusieurs paquets dans un seul repo, dépendances internes partagées.
Avec pnpm
Section intitulée « Avec pnpm »pnpm-workspace.yaml à la racine :
packages: - "apps/*" - "packages/*"Structure :
mon-monorepo/├── apps/│ ├── web/│ │ └── package.json (Next.js)│ └── mobile/│ └── package.json (React Native)├── packages/│ ├── ui/│ │ └── package.json (composants partagés)│ └── config/│ └── package.json (eslint config, tsconfig)├── pnpm-workspace.yaml└── package.json# Installer une dep dans un workspace spécifiquepnpm add react --filter web
# Lancer un script dans tous les workspacespnpm -r build
# Référencer un workspace interne dans un autre# Dans apps/web/package.json :"dependencies": { "@mon-monorepo/ui": "workspace:*"}Outils complémentaires
Section intitulée « Outils complémentaires »- Turborepo : cache et parallélisation des scripts (Vercel).
- Nx : équivalent plus complet, orienté entreprise.
Paquets globaux — à utiliser avec parcimonie
Section intitulée « Paquets globaux — à utiliser avec parcimonie »npm install -g serve # installe globalementProblème : la version globale est partagée par tous tes projets — un conflit fait des ravages. Préfère :
npx serve # exécute sans installerpnpm dlx serve # équivalent pnpmOu installe-le en devDependencies du projet et accède via un script npm.
Auto-évaluation
Section intitulée « Auto-évaluation »Pour aller plus loin
Section intitulée « Pour aller plus loin »- npm Docs — docs.npmjs.com
- pnpm Docs — pnpm.io
- Semver visualizer — semver.npmjs.com (joue avec les ranges)
- Turborepo Handbook — turbo.build/repo
- Why pnpm? — pnpm.io/motivation
Suite : 4.4 — Conteneurisation (Docker) — l’environnement reproductible au niveau du système.