pnpm (Performant npm) est un drop-in replacement de npm avec deux idées fortes : un store global sur disque qui n'a qu'une copie de chaque paquet, et une résolution stricte qui empêche les dépendances fantômes.
Pourquoi pnpm économise tant de place
Quand tu fais npm install react, npm copie les fichiers dans ton-projet/node_modules/react/. Si tu as dix projets qui utilisent React, tu as dix copies identiques sur le disque.
pnpm fait différemment :
- Il télécharge React une seule fois dans un store global (
~/.local/share/pnpm/storesur Linux/macOS,%LOCALAPPDATA%\pnpm\storesur Windows). - Dans chaque projet,
node_modules/react/est un hardlink vers les fichiers du store. Un seul fichier physique, dix projets qui y accèdent.
Concrètement : sur une machine avec dix projets React, npm occupe ~400 Mo par projet. pnpm occupe ~40 Mo (le store partagé) quel que soit le nombre de projets.
Installer pnpm
Via npm (une seule fois) :
Via corepack (inclus dans Node depuis v16) :
Vérifie :
Les commandes courantes
Installer toutes les dépendances d'un projet existant :
Ajouter un paquet :
Ajouter une devDependency :
Lancer un script défini dans package.json :
Raccourci (sans run) pour les scripts courants :
Lancer une commande ponctuelle sans installer globalement :
Mettre à jour toutes les dépendances :
Supprimer un paquet :
Résolution stricte : plus de dépendances fantômes
pnpm crée une structure node_modules/ non aplatie. Chaque paquet ne voit que ses propres dépendances déclarées. Ton code ne peut pas accéder à lodash si tu n'as pas explicitement ajouté lodash à ton package.json.
Ça peut sembler restrictif, mais c'est une sécurité : ton build est reproductible et ne dépend pas des dépendances transitives de tes dépendances.
pnpm et les monorepos
pnpm a le meilleur support de monorepos parmi les trois gestionnaires. Un fichier pnpm-workspace.yaml à la racine suffit pour déclarer plusieurs paquets :
packages:
- "packages/*"
- "apps/*"Les paquets du workspace peuvent se référencer avec workspace:* comme version :
{
"dependencies": {
"@mon-projet/shared": "workspace:*"
}
}