Pular para o conteúdo principal

node_modules planos não são a única maneira

· Leitura de 3 minutos

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_modules plano criado pelo npm e Yarn. Se você não entende por que o npm 3 teve que começar a usar node_modules planos 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:

  1. é totalmente compatível com Node.js
  2. 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.