Los nuevos usuarios de pnpm me preguntan con frecuencia sobre la extraña estructura de node_modules
que crea pnpm. ¿Por qué no es plano? ¿Dónde están todas las sub-dependencias?
Voy a suponer que los lectores del artículo ya están familiarizados con el
node_modules
plano creado por npm y Yarn. Si no entiendes por qué npm 3 tuvo que empezar a usar planosnode_modules
en v3, puedes encontrar algo de prehistoria en ¿Por qué debemos usar pnpm? (en inglés).
Entonces, ¿por qué es inusual el node_modules de pnpm
? Vamos a crear dos directorios y ejecutar npm add express
en uno de ellos y pnpm add express
en el otro. Aquí está la parte superior de lo que obtienes en node_modules
del primer directorio:
.bin
accepts
array-flatten
body-parser
bytes
content-disposition
cookie-signature
cookie
debug
depd
destroy
ee-first
encodeurl
escape-html
etag
express
Puedes ver todo el directorio aquí.
Y esto es lo que obtienes en los node_modules
creados por pnpm:
.pnpm
.modules.yaml
express
Puedes comprobarlo aquí.
Entonces, ¿dónde están todas las sub-dependencias? Solo hay una carpeta en node_modules
llamada .pnpm
y un enlace simbólico llamado express
. Bueno, solo hemos instalado express
, así que este es el único paquete al que tu aplicación tiene que tener acceso
Lea más sobre por qué la rigurosidad de pnpm es algo bueno aquí (en inglés)
Veamos qué hay dentro de express
:
▾ node_modules
▸ .pnpm
▾ express
▸ lib
History.md
index.js
LICENSE
package.json
Readme.md
.modules.yaml
¿express
no tiene node_modules
? ¿Dónde están todas las dependencias de express
?
El truco está en que express
es sólo un enlace simbólico. Cuando Node.js resuelve las dependencias, usa sus ubicaciones reales, por lo que no conserva los enlaces simbólicos. Pero, ¿dónde está la ubicación real de express
, podrías preguntarte?
Aquí: node_modules/.pnpm/express@4.17.1/node_modules/express.
OK, ahora conocemos el propósito de la carpeta .pnpm/
. .pnpm/
almacena todos los paquetes en una estructura de carpetas plana, por lo que cada paquete se puede encontrar en una carpeta nombrada con este patrón:
.pnpm/<name>@<version>/node_modules/<name>
Lo llamamos el directorio de almacenamiento virtual.
Esta estructura plana evita los problemas de ruta larga causados por los node_modules
anidados creados por npm v2, pero mantiene los paquetes aislados a diferencia de los node_modules
planos creados por npm v3,4,5,6 o Yarn v1.
Ahora veamos la ubicación real de express
:
▾ express
▸ lib
History.md
index.js
LICENSE
package.json
Readme.md
¿Es una estafa? ¡Todavía le falta node_modules
! El segundo truco de la estructura de node_modules
de pnpm es que las dependencias de los paquetes están en el mismo nivel de directorio en el que se encuentra la ubicación real del paquete dependiente. Así que las dependencias de express
no están en .pnpm/express@4.17.1/node_modules/express/node_modules/
sino en .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
Todas las dependencias de express
son enlaces simbólicos a los directorios apropiados en node_modules/.pnpm/
. Colocar dependencias de expreso
en un nivel superior permite evitar enlaces simbólicos circulares.
Así que como puedes ver, a pesar de que la estructura node_modules
de pnpm parece inusual al principio:
- es completamente compatible con Node.js
- los paquetes están bien agrupados con sus dependencias
La estructura es un poco más compleja para paquetes con dependencias entre pares, pero la idea es la misma: usar enlaces simbólicos para crear un anidamiento con una estructura de directorio plana.