Passer au contenu principal

Flat node_modules n'est pas le seul moyen

· 3 mins à lire

Les nouveaux utilisateurs de pnpm me posent souvent des questions sur la structure bizarre du dossier node_modules que pnpm créé. Pourquoi n'est-il pas plat ? Où sont toutes les sous-dépendances ?

Je vais supposer que les lecteurs de cet article sont déjà familiers avec les node_modules plats créés par npm et Yarn. Si vous ne comprenez pas pourquoi npm 3 a dû commencer à utiliser node_modules en v3, vous pouvez trouver un peu de préhistoire dans Pourquoi devrait-on utiliser pnpm ?.

Alors pourquoi les node_modules de pnpm sont inhabituels ? Créons deux répertoires et éxecutons npm add express dans l'un d'eux et pnpm add express dans l'autre. Voilà ce que vous obtenez dans le node_modules du premier répertoire:

.bin
accepts
array-flatten
body-parser
bytes
content-disposition
cookie-signature
cookie
debug
depd
destroy
ee-first
encodeurl
escape-html
etag
express

Vous pouvez voir tout le répertoire ici.

Et voici ce que vous obtenez dans les node_modules créés par pnpm:

.pnpm
.modules.yaml
express

Vous pouvez vérifier ici.

Alors, où sont toues les dépendances ? Il y a qu'un seul dossier dans les node_modules appelé .pnpm et il y a un lien symbolique appelé express. Et bien, nous n'avons installé que express, c'est donc le seul package auquel votre application doit avoir accès

En savoir plus sur pourquoi la rigueur de pnpm est une bonne chose ici

Voyons ce qu'il y a à l'intérieur d'express:

▾ node_modules
▸ .pnpm
▾ express
▸ lib
History.md
index.js
LICENSE
package.json
Readme.md
.modules.yaml

express n'a pas de node_modules ? Où sont toutes les dépendances d'express ?

L'astuce est qu'express n'est qu'un lien symbolique. Lorsque Node.js résout les dépendances, il utilise leurs emplacements réels, il ne conserve donc pas les liens symboliques. Mais où est l'emplacement réel d'express, vous vous demandez ?

Ici: node_modules/.pnpm/express@4.17.1/node_modules/express.

OK, alors maintenant nous connaissons l'utilité du dossier .pnpm/. .pnpm/ stocke tous les packages dans une structure de dossiers plats, de sorte que chaque package peut être trouvé dans un dossier nommé par ce modèle:

.pnpm/<name>@<version>/node_modules/<name>

On appelle ça le dossier du stockage virtuel.

Cette structure plate évite les problèmes de long chemin causés par les node_modules créés par npm v2 mais maintient les packages isolés, contrairement aux node_modules plats créés par npm v 3, 4, 5, 6 ou bien Yarn v1.

Regardons maintenant le réel emplacement d'express:

  ▾ express
▸ lib
History.md
index.js
LICENSE
package.json
Readme.md

Est-ce une arnaque ? Il manque encore node_modules ! La deuxième astuce de la structure des node_modules de pnpm est que les dépendances des packages se trouvent au même niveau de répertoire que l'emplacement réel du package dépendant. Donc les dépendances d'express ne sont pas dans .pnpm/express@4.17.1/node_modules/express/node_modules/ mais dans .pnpm/express@4.17.1/node_modules/:

▾ node_modules
▾ .pnpm
▸ accepts@1.3.5
▸ array-flatten@1.1.1
...
▾ express@4.16.3
▾ node_modules
▸ accepts
▸ array-flatten
▸ body-parser
▸ content-disposition
...
▸ etag
▾ express
▸ lib
History.md
index.js
LICENSE
package.json
Readme.md

Toutes les dépendances d'express sont des liens symboliques vers des dossiers appropriés dans node_modules/.pnpm/. Placer les dépendances d'express un niveau supérieur permet d'éviter les liens symboliques circulaires.

Donc, comme vous pouvez le voir, même si la structure node_modules pnpm semble inhabituelle au premier abord:

  1. il est complètement compatible avec Node.js
  2. les packages sont bien regroupés avec leurs dépendances

La structure est un peu plus complexe pour les packages avec des dépendances paires mais l'idée est la même: utiliser des liens symboliques pour créer une imbrication avec une structure de dossier plate.