Executando verificação de segurança...
10

Por que o npm cria um ".bin" dentro da node_modules?

Falaaaa pessoal! Escrevendo aqui meu primeiro post no TabNews, estou felizão!

Estava revisitando alguns conceitos do NPM e Ecossistema Node.js e achei que isso seria um artigo legal para postar:

Por que o npm cria um diretório ".bin" dentro da node_modules?

Dentro do diretório .bin ficam os scripts de CLI (Command Line Interface) para que o nosso projeto possa executar comandos no terminal.
Isso foi criado porque as bibliotecas, às vezes, precisam alterar ou listar arquivos — e isso só pode ser feito via terminal. Nesse diretório .bin são gerados scripts específicos para cada sistema operacional (Linux, Windows ou macOS).
Essa abordagem garante que o ecossistema Node seja compatível com diferentes ambientes.

Porém, se quiséssemos executar esses scripts manualmente, precisaríamos referenciar o caminho completo do arquivo. Por exemplo:

./node_modules/.bin/script

Agora imagine bibliotecas mais complexas, em que precisamos passar várias flags e parâmetros — isso seria bem trabalhoso, certo?

Pensando nisso, o npm criou uma seção no arquivo package.json chamada "scripts", onde podemos criar aliases (atalhos) para esses comandos. Esses comandos são acessíveis apenas dentro do escopo do projeto.
Isso é possível porque o package.json “enxerga” o diretório .bin dentro de node_modules, então basta usarmos o nome do script, sem precisar escrever o caminho completo.

Vamos a um exemplo.
Usaremos o famoso linter de código chamado ESLint.

Após instalá-lo, se quiséssemos executá-lo sem o package.json, faríamos assim:

./node_modules/.bin/eslint .

Mas, com o script configurado no package.json:

{
  "name": "learning-about-automations-npm",
  "version": "1.0.0",
  "description": "Project to learn about npm automations",
  "license": "ISC",
  "author": "PedroRCSilva",
  "type": "module",
  "main": "index.js",
  "scripts": {
    "lint": "eslint ." <---
  },
  "dependencies": {},
  "devDependencies": {
    "eslint": "^9.37.0"
  }
}

Podemos simplesmente executar:

npm run lint

Com isso, conseguimos configurar uma infinidade de comandos e automações usando o npm.

Carregando publicação patrocinada...
2

Excelente post, Pedro! 👏

Esse é um daqueles conceitos que a gente usa todo dia mas pouca gente para pra pensar no "como" e "porquê" funciona.
Lembro quando comecei com Node.js e ficava me perguntando como que magicamente o npm run conseguia encontrar os comandos sem eu precisar digitar aquele caminhão de caminho relativo.

E pior, já peguei projeto antigo onde o pessoal instalava as ferramentas de CLI globalmente (npm install -g) e dava aquela dor de cabeça quando a versão global era diferente da do projeto... O .bin resolve justamente isso, mantendo o binário específico da versão que você instalou no projeto.
Seu exemplo com ESLint foi perfeito! É exatamente isso que acontece com o jest, webpack, typescript e tantas outras ferramentas.

1

Muito obrigado! Realmente, quando paramos para entender como as coisas funcionam soltamos a típica frase: "Haaaa, agora tudo faz sentido" hahhaha. Fico feliz que tenha curtido.

1

Caramba, que tema peculiar! Sempre vi o tal do .bin perdido ali no node_modules e nunca tinha parado pra pensar no que ele realmente fazia. Curioso como algo tão “escondido” tem um papel importante pra conversar direto com o SO e facilitar nossos processos. Curti!

1

Bizarro né? Porém, faz total diferença quando estamos criando uma aplicação em Node ou criando nossa própria lib. Fico feliz que tenha gostado!

0
0