devops
pnpm pour un monorepo, et le piège des dépendances fantômes qu'il ferme
pnpm pour un monorepo, et le piège des dépendances fantômes qu'il ferme
Le trait déterminant de pnpm est un store global adressable par contenu : chaque version de paquet est stockée une fois sur disque, et chaque projet obtient un lien dur vers son node_modules local plutôt que sa propre copie complète. Dans un monorepo avec trois applications React + Vite quasi identiques plus un back-end, partageant toutes l'essentiel du même arbre de dépendances, c'est une différence mesurable en usage disque et en vitesse d'installation, pas une préférence marginale.
# pnpm-workspace.yaml
packages:
- "apps/*"
- "packages/*"
Ça laisse apps/web dépendre de packages/api via "@app/api": "workspace:*" — un vrai symlink vivant vers le paquet local, pas une version publiée. Édite le paquet, et après sa propre étape de build chaque application qui en dépend voit le changement immédiatement.
pnpm --filter @app/types build
pnpm --filter web dev
Cadre une commande à un seul paquet de workspace plutôt qu'à chaque paquet du monorepo — essentiel dès qu'il y a plusieurs applications.
La rigueur est le cœur
La structure node_modules de pnpm est intentionnellement plus stricte que celle de npm ou yarn : un paquet ne peut importer que ce qu'il a explicitement déclaré comme dépendance, pas quelque chose qui se trouve juste être hissé à proximité. Le hoisting plus plat de npm/yarn peut laisser un projet marcher par accident en dépendant d'un paquet qu'il n'a jamais déclaré, juste parce qu'un frère l'a tiré — une dépendance fantôme qui marche par accident et casse de façon imprévisible dès que l'arbre du frère change. pnpm fait remonter ça à l'installation ou au build au lieu d'une défaillance mystérieuse à l'exécution découverte plus tard, souvent dans l'environnement de quelqu'un d'autre.
pnpm install --frozen-lockfile
Fait échouer l'installation purement et simplement si le lockfile ne correspond pas déjà au package.json, plutôt que de le régénérer silencieusement. C'est ce qui garantit que la CI installe les versions exactes réellement testées et commitées.
"packageManager": "[email protected]"
Épingle la version exacte de pnpm via Corepack, pour que deux machines — ou une machine locale et un runner CI — ne résolvent pas les dépendances légèrement différemment entre versions de pnpm.