node_modules planos não são a única maneira
Novos usuários do pnpm frequentemente me perguntam acerca da estranha estrutura do node_modules que o pnpm cria. Por que não é plano? Onde estão todas as sub-dependências?
Vou assumir que os leitores do artigo já estão familiarizados com o
node_modulesplano criado pelo npm e Yarn. Se você não entende por que o npm 3 teve que começar a usarnode_modulesplanos na v3, você pode encontrar um pouco da história em Por que devemos usar o pnpm?.
Então, por que o node_modules do pnpm é incomum? Vamos criar dois diretórios e executar npm add express em um deles e pnpm add express no outro. Aqui está o início do node_modules do primeiro diretório:
.bin
accepts
array-flatten
body-parser
bytes
content-disposition
cookie-signature
cookie
debug
depd
destroy
ee-first
encodeurl
escape-html
etag
express
Você pode ver todo o diretório aqui.
E é isso que você obtém no node_modules criado pelo pnpm:
.pnpm
.modules.yaml
express
Você pode conferir aqui.
Então, onde estão todas as dependências? Existe apenas uma pasta em node_modules chamada .pnpm e um link simbólico chamado express. Bem, instalamos apenas express, então esse é o único pacote que sua aplicação tem que ter acesso
Leia mais sobre porque o rigor do pnpm é uma coisa boa aqui
Vamos ver o que está dentro de express:
▾ node_modules
▸ .pnpm
▾ express
▸ lib
History.md
index.js
LICENSE
package.json
Readme.md
.modules.yaml
express não tem node_modules? Onde estão todas as dependências de express?
O truque é que express é apenas um link simbólico. Quando o Node.js resolve dependências, ele usa suas localizações reais, portanto, não preserva links simbólicos. Mas onde está a localização real de express, você pode perguntar?
Aqui: node_modules/.pnpm/express@4.17.1/node_modules/express.
OK, agora sabemos o propósito da pasta .pnpm/. .pnpm/ armazena todos os pacotes em uma estrutura de pastas simples, então cada pacote pode ser encontrado em uma pasta nomeada por este padrão:
.pnpm/<name>@<version>/node_modules/<name>
Nós o chamamos de virtual store directory.
Essa estrutura plana evita os problemas de longos diretórios causados pelo node_modules aninhados criado pelo npm v2, mas mantém os pacotes isolados ao contrário dos node_modules criados pelo npm v3,4,5,6 ou Yarn v1.
Agora vamos olhar para a localização real de express:
▾ express
▸ lib
History.md
index.js
LICENSE
package.json
Readme.md
É uma farsa? Ainda falta node_modules! O segundo truque da estrutura node_modules do pnpm é que as dependências dos pacotes estão no mesmo nível de diretório em que a localização real da dependência. Portanto, as dependências de express não estão em .pnpm/express@4.17.1/node_modules/express/node_modules/ mas em .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 as dependências de express são links simbólicos para diretórios apropriados em node_modules/.pnpm/. Colocar dependências de express um nível acima permite evitar links simbólicos circulares.
Então, como você pode ver, mesmo que o node_modules do pnpm pareça incomum no início:
- é totalmente compatível com Node.js
- os pacotes são bem agrupados com suas dependências
A estrutura é um pouco mais complexa para pacotes com dependências peer, mas a ideia é a mesma: usar links simbólicos para criar um aninhamento com uma estrutura de diretório simples.