Conhecendo mais sobre o NPM

Conhecendo mais sobre o NPM

Nas lições mais avançadas desta jornada, é necessário que você tenha um pré-entendimento sobre o funcionamento do gerenciador de pacotes do NodeJS, o NPM!

Lá na lição que fala sobre Configurações Iniciais, você conheceu um pouco sobre o que é o NPM, e como ele pode atuar na sua aplicação.

Nesta lição, vamos nos aprofundar um pouco mais no universo do NPM, de modo a criar projetos com ele, gerenciar pacotes, instalar pacotes, remover pacotes, criar scripts e muito mais!

Vamos nessa? 🤓

O que é o NPM?

O NPM (Node Package Manager) é o principal gerenciador de pacotes que é usado pela plataforma do NodeJS.

É por meio dele que conseguiremos realizar a instalação de nossos pacotes, atualização dos mesmos, e o gerenciamento de bibliotecas e ferramentas de código de terceiros na sua aplicação.

A grande maioria dos projetos que você for participar, você irá notar que a grande maioria dele faz o uso do NPM para o gerenciamento de pacotes.

Pensa no NPM como uma ponte capaz de trazer bibliotecas de terceiros para seu próprio projeto, e também as manter atualizadas, a cada nova funcionalidade que o dono da biblioteca for publicando no seu repositório online.

O NPM é parecido com o Windows Update da Microsoft, que tem por objetivo, manter todas as atualizações do Windows, além de nos dar a possibilidade de instalar/atualizar/remover novas funcionalidades e recursos, onde tudo isso feito é feito de forma automática.

Além disso, com o NPM, nós podemos configurar nosso projeto de tal modo que ele consiga rodar scripts por meio do próprio NPM.

Portanto, com o NPM você pode:

  • Adicionar bibliotecas e ferramentas ao seu projeto por meio de um simples comando (npm install).
  • Manter um arquivo package.json que lista todas as dependências do seu projeto, facilitando a instalação de todas as bibliotecas necessárias com um único comando.
  • Se você desenvolveu uma biblioteca ou ferramenta que deseja compartilhar com a comunidade, poderá publicá-la no repositório NPM para que outros possam fazer o seu uso.

Observação: Além do NPM, temos outros pacotes disponívels no mercado, como é o caso do Yarn.

É importante ressaltar que raramente um projeto feito com NodeJS, usufrua somente dos core modules disponibilizados pelo próprio ambiente. Por esse motivo, o uso do NPM se faz totalmente necessário na sua aplicação.

Não existe um core module que valide o seu CPF, por exemplo... mas existem diversos pacotes externos que fazem isso, e talvez você queira utilizá-los na sua aplicação... ou você prefere perder muito tempo reinventado a roda?

Bem, agora que você já sabe a importância do NPM no seu projeto em NodeJS, vamos parar um pouquinho, e fazer uma pequena reflexão 🤔

Usar pacotes prontos, ou criá-los do zero?

No início da minha carreira como desenvolvedor de software, eu sempre ouvia muito a frase: "não reinvente a roda!", e sabe qual era a minha resposta?

"A RODA PRECISA SER REINVENTADA SIM!".

E até hoje uma parte de mim ainda acredita nisso, pois no final das contas, eu sempre me enxia de orgulho, batia no peito e dizia: "Eu fiz 100% desse sistema, sem precisar instalar nenhuma biblioteca de terceiros!".

E isso era bom, não vou mentir... dava uma sensação de saciamento danado 😅

Porque no final das contas, as pessoas sempre olhavam pra mim e diziam: "Nossa, como você é um gênio...", já outras... "Cara, porque você perdeu tempo com isso?".

É claro que o processo de aprendizado é muito maior quando você decide criar uma biblioteca do absoluto ZERO, ou seja, por meio de funções da própria linguagem e com muuuuita lógica envolvida 🤓

Entretanto, lá no ano de 2015, quando eu tive uma startup acelerada pela Universidade Estácio, chamada de Estácio Nave.

A minha visão começou a mudar um pouco, o que antes eu considerava uma verdade absoluta, aos poucos foi caindo por terra.

A principal delas foi o fato de eu sempre criar minhas próprias bibliotecas do ZERO ABSOLUTO, tipo de coisa que pra mim demandava muito tempo.

E não era apenas as biblioteas, eram os layouts e até mesmo questões de arquitetura 🫣

E se fosse possível, eu criava a minha própria linguagem de programação para ser usada especificiamente naquele projeto (sim, eu tinha umas neuras) 😅

Com o tempo, eu fui percebendo que esse "modus operandis", demandava muito tempo para um tipo de coisa que NÃO INTERESSARIA para meu usuário final.

Ao mesmo tempo que fui percebendo que isso não influênciava em nada no produto final, e que na verdade eu estava era PERDENDO TEMPO 🕖

Uma vez que meus usuários, eles não estavam interessados em saber se a minha aplicação usava PHP, NodeJS, NPM, Yarn, biblioteca de Fulano de Tal e qualquer outra coisa que não foi criada por mim.

Para o usuário final, o que importava para ele, era se a minha SOLUÇÃO resolvia os problemas DELE! Independentemente do que estava sendo feito por de baixo dos panos.

E outra, você não tem a obrigação de deixar explícito que você fez o uso da biblioteca de fulano de tal, de ciclano, ou de beltrano. Até porque, no final das contas, 98% das pessoas nem saberão que você fez ou faz o uso dessas bibliotecas.

E foi aí que eu comecei a pensar: "Cara, eu to perdendo muito tempo criando uma solução de total autoria, enquanto eu poderia cortar caminho usando pacotes já existentes, e focar no meu objetivo PRIMÁRIO...".

Desde então, meu mindset mudou, e se der pra fazer uso de uma biblioteca de um terceiro, ou de um template pronto, por que não?

Mas daí você pode me perguntar: "E quando começa a fazer sentido eu criar um pacote do ZERO ?".

No meu ponto de vista, só existem duas alternativas que fazem sentido (pra mim) criar pacotes do ZERO:

  • Quando você está criando uma solução bem específica, ao mesmo tempo que as soluções e pacotes atuais não te atendem.
  • Quando você tem um pé na filantropia, e gosta de ajudar a comunidade de tal modo, que lança suas próprias bibliotecas (código aberto) visando facilitar a vida dos outros desenvolvedores (Exemplo: Pupperter).

É importante que você entenda que a última opção, na maioria das vezes, não te trará retornos financeiros 🫥

Mas... pode fazer com que a sua biblioteca fique famosa a tal ponto, de você receber uma proposta de emprego de uma BIG TECH (Google, Tesla, Facebook, Twitter...), e eu já vi isso acontecer 🤩

Eu por exemplo, há alguns anos atrás lancei um pacote de Streaming de Vídeos para o Laravel, pois naquela época eu não tinha encontrado nenhum pacote que pudesse atender minha aplicação, e como eu também tenho um pé na filantropia, lancei esse pacote para o público em geral 🙂

Até agora não recebi nenhum tostão com ele, muito menos uma proposta de uma Big Tech 😂

Mas o simples fato de algumas pessoas o terem baixado, e como consequência terem solucionado seus problemas (eu acho, porque não tem como saber direito), já é uma coisa que me deixa feliz, ao mesmo tempo, que é um tipo de coisa que dá pra colocar no currículo também, não é verdade?

Se você for parar para pensar, hoje vivemos na Cultura do Remix, onde nada se cria... tudo se remixa. Dificilmente uma nova ideia surge sem qualquer tipo de base fundamentada.

É igual na matemática, que apesar de termos inúmeras fórmulas, elas sempre se resumem nos fundamentos que já são conhecidos, como a adição, diminuição, multiplicação e divisão.

Dito isso, cabe a você (leitor) tirar suas próprias conclusões, se vale a pena ou não criar pacotes do zero, ou fazer o uso de pacotes de terceiros!

Fica aí a reflexão final 😉

Criando um projeto com NPM

Por meio do NPM, você também pode criar um novo projeto do ZERO, onde este pode conter alguns pacotes e configurações inciais que serão usadas pela sua aplicação.

Para testarmos isso, primeiro você precisa garantir que o pacote NPM já está instalado na sua máquina.

Para fazer essa verificação, abra o seu terminal (Prompt de Comando) e execute o seguinte código:

npm -v

Se tudo estiver configurado corretamente, o terminal irá retornar a versão atual do NPM que está instalado na sua máquina:

Observação: Caso seja necessário atualizar a sua versão do NPM para a mais recente, basta utilizar o seguinte comando no seu terminal:

npm install -g npm

Em seguida, não se esqueça de executar um npm -v, para checar se está tudo certo.

Como nessa seção nós iremos trabalhar exclusivamente com o NPM, nada mais justo que criar uma nova pasta no seu computador para agrupar os projetos que iremos criar nesta lição 😉

No meu caso, como estou usando Windows, eu criei uma nova pasta chamada projetosNPM na minha área de trabalho (desktop):

Feito isso, com o seu terminal (Prompt de Comando) aberto dentro da pasta que acabamos de criar (projetosNPM), vamos iniciar um novo projeto por meio do seguinte comando:

npm init

Como você pode ver na ilustração acima, o gerenciador de pacotes gerou uma mensagem de boas vindas, e logo em seguida, pediu para que informássemos o nome do nosso projeto (package name).

De maneira automática, ele induz que o nome do seu pacote (package name) seja o mesmo nome da pasta (em minúsculo).

👉 Aqui você pode pressionar [ENTER], e deixar que o NPM use o nome da sua pasta como o nome do seu pacote (recomendável).

👉 Ou você pode informar um nome customizado, e pressionar [ENTER]. Lembre-se de usar letras minúsculas e traços em vez de espaços.

A segunda opção, refere-se a versão atual (version) do seu projeto. E como estamos criando-o pela primeira vez, nada mais justo que deixar 1.0.0, ou caso preferir, você pode digitar uma versão customizada. (Por exemplo: 0.0.0 ou 0.0.1)

A description, refere-se a descrição do seu projeto, o ideal é que você explique em poucas palavras sobre o que o seu projeto se trata.

Já o Entry Point, refere-se ao ponto de entrada da sua aplicação, que pode ser desde o arquivo index.js, server.js, app.js e entre outros.

Lembra que eu falei que nós podemos executar nossa aplicação em NodeJS diretamente pelo NPM?

Isso geralmente é feito pelo npm start (spoilers), que por sua vez, por de baixo dos panos, executa o comando node ./app.js e roda a sua aplicação.

No meu caso, eu deixei meu Entry Point como index.js, mas você pode mudar ele mais tarde se quiser 😌 (assim como qualquer outra configuração que fizemos até o momento)

O Test Command é usado para informar o arquivo principal que irá rodar testes automatizados na sua aplicação.

Como não iremos trabalhar com isso no momento, vamos deixá-lo em branco.

O Git Repository é o local aonde você insere a URL do repositório que está relacionado com esse projeto.

Se você já tem um repositório Git criado (por exemplo, no GitHub, GitLab, Bitbucket, etc.), coloque a URL do repositório no campo "git repository". A URL pode ser algo como https://github.com/usuario/repositorio.git.

Mas como eu não tenho um repositório no Git dedicado a este projeto, vou deixar em branco, e seguir em frente.

Já as keywords, nada mais são do que os termos (palavras-chave) que identificam o seu projeto.

Se tivéssemos um projeto de dashboard por exemplo, poderiamos usar os termos: dash, dashboard, panel, admin, bootstrap, UX (você deve separar as palavras-chave por vírgula dentro de keywords).

Como estamos configurando um projeto simples, usei apenas os termos npm, inicio.

Como o próprio nome já nos diz, Author refere-se ao nome da pessoa que criou o projeto. Então nada mais justo que colocar o seu próprio nome (espaços e caracteres especiais são aceitos).

O Licence (licensa) refere-se a forma com que os outros desenvolvedores poderão usar o seu código, o que define como o código pode ser utilizado, modificado e distribuído. Aqui você pode inserir as seguintes opções:

ISC: a licença ISC permite que você use, modifique, copie e distribua o código com muitas poucas restrições. É uma das licenças mais permissivas disponíveis que temos no mercado atualmente.

MIT: permite quase qualquer coisa com o código, incluindo modificar, distribuir e usar em projetos comerciais.

Apache License 2.0: semelhante à MIT, mas inclui uma cláusula de patente que protege contra ações legais baseadas em patentes.

GNU General Public License (GPL): exige que qualquer software derivado também seja distribuído sob a mesma licença, garantindo que as liberdades concedidas pela licença sejam preservadas em projetos derivados.

BSD License: permite usar, modificar e distribuir o código com poucas restrições.

Creative Commons (CC): mais comum em obras criativas, como textos e imagens, do que para software.

No meu caso, deixei como ISC mesmo...

Por fim, o terminal perguntará se tudo o que você informou está correto, e se sim, digite o termo yes no terminal e pressione [ENTER].

Observação: qualquer outro comando que você digitar, fará com que você volte a etapa inicial para corrigir suas informações.

Após isso, o assistente de configuração do NPM será fechado, e dentro da pasta projetosNPM, será criado um novo arquivo chamado de package.json, que contém as mesmas configurações que acabamos de criar, só que no formato JSON 😆

package.json:

{
  "name": "projetosnpm",
  "version": "1.0.0",
  "description": "Um projeto de testes feito com NPM",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [
    "npm",
    "inicio"
  ],
  "author": "Micilini Roll",
  "license": "ISC"
}

Feito isso, vamos entender um pouco mais sobre esse arquivo 🤓

O que é o package.json?

O package.json é um arquivo gerenciado pelo NPM, que é fundamental em projetos que fazem o uso da linguagem Javascript ou Typescript.

Ele atua como o coração do seu projeto, gerenciando informações essenciais sobre o projeto e suas dependências.

É por meio dele que o NPM sabe quais scripts executar, além das bibliotecas que estão instaladas. Pensa nesse arquivo como uma especie de controle de caixa, que lista todos os produtos que você possui na sua loja:

Ou seja, o package.json é um documento de controle, e sem ele, não temos controle de nada, simples!

O arquivo package.json possui alguns metados principais:

name: nome do projeto.

version: versão atual do projeto.

description: uma breve descrição do projeto.

author: informações sobre o autor do projeto.

license: tipo de licença do projeto (por exemplo, MIT, Apache-2.0).

keywords: palavras-chave associadas ao projeto que ajudam na descoberta.

browserslist: configura quais navegadores são suportados pelo projeto, útil para ferramentas como Babel e Autoprefixer.

files: lista arquivos e diretórios a serem incluídos quando o pacote é publicado.

Além disso, a seção scripts permite definir comandos personalizados que você pode executar com npm run [script-name].

Observe alguns exemplos:

"scripts": {
  "start": "node index.js",
  "test": "jest",
  "build": "webpack"
}

Lembra que eu falei que o comando npm start executa o seu código em NodeJS? Então... olha ele ali executando o node index.js, por de baixo dos panos 😉

Observando o funcionamento desse arquivo JSON, acredito que ficou claro como ele funciona, cert?

Note que na estrutura acima, quando o desenvolvedor executar um npm test, a biblioteca jest será chamada (ela pode estar associada a um arquivo global de testes).

Da mesma forma que npm build, vai chamar a biblioteca webpack para compilar o nosso projeto.

Lembrando que quando digitamos npm + [start, test, build], por de baixo dos panos, o NPM irá procurar pela chave "script" de modo a achar as sub-chaves "start, test e build".

Dentro do JSON, podemos ter uma seção dedicada a dependências:

"dependencies": {
  "express": "^4.17.1"
},
"devDependencies": {
  "jest": "^26.6.3"
}

Que lista todas as bibliotecas necessárias para o funcionamento do projeto em produção. Essas dependências serão instaladas quando você for executar o comando npm install.

Já o devDependencies, é mais voltada aos pacotes que são necessários, apenas para o ambiente de desenvolvimento.

Por fim, nós podemos ter também, outras configurações avançadas relacionadas ao nosso projeto:

"main": "index.js",
"engines": {
  "node": ">=14.0.0"
},
"repository": {
  "type": "git",
  "url": "https://github.com/usuario/repositorio.git"
}

main: o ponto de entrada principal do seu projeto, geralmente um arquivo JavaScript que é executado quando o módulo é requerido.

engines: especifica quais versões do NodeJS ou outros ambientes são suportados pelo seu projeto.

repository: informações sobre o repositório do código-fonte (como a URL do Git).

Caso você queira resetar as configurações feitas pelo npm, basta apagar o arquivo package.json, e executar o assistente de configuração usando o comando npm init.

Criando um projeto com NPM de forma enxuta

Caso você queira pular a maioria daquelas configurações do assistente de configuração. Existe uma maneira mais rápida de criar seu projeto com NPM.

Para isso, basta executar o seguinte comando dentro da pasta raiz do seu projeto:

npm init -y

Por meio da flag -y, o NPM irá fazer com que todas as respostas sejam marcadas YES,  o que é equivalente a sairmos pressionando [ENTER] em todas as perguntas 🤣

O ponto bom, é que isso facilita a criação do nosso projeto, visto que podemos alterar o arquivo packge.json com calma mais tarde 😌

Observação: Você pode utilizar o comando npm init --yes, que funciona da mesma forma como o npm init -y.

Instalando seu primeiro pacote

O processo de instalação de um pacote dentro do seu projeto, é a coisa mais simples do mundo, primeiro, certifique-se de que o seu terminal (Prompt de Comando) esteja aberto na pasta raiz do seu projeto (mesma pasta onde contém o arquivo package.json), e em seguida, basta digitar o seguinte comando:

npm install <nome-do-pacote>

Existe uma versão mais enxuta, na qual não precisamos digitar o termo install, basta usar apenas a letra i da seguinte forma:

npm i <nome-do-pacote>

Onde está escrito <nome-do-pacote>, você irá trocar para o nome do pacote que você deseja instalar.

página principal do NPM:

Existe um campo de busca atrelado ao cabeçalho da página. Ali, nós podemos pesquisar por todos os pacotes existentes no banco de dados do NPM.

Vamos pegar como exemplo, o meu pacote favorito, o Puppeteer:

Na parte direita, você consegue ver um bloco de instalação (install), que contém o seguinte comando:

npm i puppeteer

Lembrando que o processo de instalação pode demorar um pouco, e isso depende também da sua conexão com a internet.

puppeteer é o nome do nosso pacote, e executando o comando acima na pasta raiz do seu projeto, fará com que essa biblioteca seja instalada dentro de uma pasta chamada de node_modules. 

Ao mesmo tempo que um novo arquivo chamado de package-lock.json será criado.

A pasta node_modules é onde o NPM (Node Package Manager) instala todas as dependências do seu projeto, ou seja, é pra lá que vai o código-fonte das bibliotecas de terceiros.

Quando você executa o comando npm install, o NPM faz download daqueles pacotes, e os coloca nesta pasta.

Essa pasta é considerada a maior pasta do projeto! Logo, costuma ser a pasta mais pesada!

O package-lock.json é um arquivo gerado automaticamente quando você executa npm install. Ele contém um registro detalhado de todas as versões exatas das dependências instaladas no projeto.

Além disso, após a execução do comando npm install, o arquivo package.json também sofrerá alterações, você consegue identificar quais foram?

{
  "name": "projetosnpm",
  "version": "1.0.0",
  "description": "Um projeto de testes feito com NPM",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [
    "npm",
    "inicio"
  ],
  "author": "Micilini Roll",
  "license": "ISC",
  "dependencies": {
    "puppeteer": "^23.2.0"
  }
}

Note que a chave "puppeteer" contendo a versão atual (acima de 23.2.0) foi inclusa neste arquivo. O que indica que o projeto depende do pacote Puppeteer 😉

Vamos ver outros exemplos de pacotes que podemos instalar:

npm i express
npm i cors
npm i cpf

express: é um framework web que iremos aprender na próxima lição 🤫 (sem spoilers dessa vez, ok?)

cors: é um pacote que gerencia a política de CORS do navegador do cliente e servidor.

cpf: é um pacote completo que é capaz de validar e gerar CPF.

Acessando a documentação de um pacote

O NPM possui um recurso muito legal chamado de docs, que pode ser usado para retornar a documentação relacionada ao pacote. Veja como podemos fazer isso:

npm docs <nome-do-pacote>

No comando acima, usamos o docs para acessar a documentação do pacote.

Geralmente, ele abre uma nova aba no nosso navegador, apontando para a página de documentação daquele pacote (principalmente se for um pacote grande).

Acessando a Home do pacote

Cada pacote do NPM, pode ter sua própria Home Page (página principal) associado a ele, e geralmente acessamos ela por meio do seguinte comando:

npm home <nome-do-pacote>

Com o comando home, você pode ser direcionado, ou para a página de documentação relacionada à aquele pacote, ou quem sabe para uma página de apresentação do pacote em sí, onde mostra quais problemas ele se propõe a resolver.

Lembando que isso vai variar de pacote para pacote, existe alguns que só configuram a página de documentação, já outros que trabalham com ambas (e alguns que nem isso tem 😂).

Usando o npm install

Você também pode executar o comando npm install sem a necessidade de informar o nome do seu pacote, sabia disso?

Quando você executa o comando npm install sem especificar um nome de pacote, o NPM instala todas as dependências listadas no arquivo package.json do seu projeto.

Para vermos o funcionamento disso, vamos excluir a pasta node_modules e o arquivo package-lock.json, deixando apenas o arquivo package.json na pasta raiz do projeto:

Como já fizemos a instalação da biblioteca Puppeteer em nosso projeto, o arquivo package.json ainda vai conter o registro dessa dependência:

"dependencies": {
  "puppeteer": "^23.2.0"
}

De modo que, quando executarmos um npm install, o gerenciador abra esse arquivo (package.json), identifique as dependencias necessárias, verifique se elas já estão instaladas, e caso não estiverem, ele realiza o download de cada uma delas:

Se você observar, alguns pacotes possuem alguns sinais, como ^ e ~, mas para que eles servem? 🤨

Sinal ^ (Caret)

O sinal ^ indica que o NPM pode atualizar a versão da dependência para qualquer versão que não altere o primeiro número não zero à esquerda do ponto decimal.

Sendo assim, ele permite atualizações como: 1.2.x, 1.x.x, mas não 2.0.0 ou superior.

Por exemplo, se a dependência estiver especificada como ^1.2.3, o NPM instalará a versão mais recente que é 1.x.x onde o x pode ser qualquer valor (exemplo: 1.2.4, 1.9.9...), mas não versões 2.0.0 ou superiores.

Isso permite que o projeto receba atualizações de correções e novas funcionalidades que não quebram a compatibilidade, mas mantém a versão principal a mesma.

"dependencies": {
  "example-package": "^1.2.3",
}

"Não quebram a compatibilidade" no sentido de versão 1.x.x manterem a mesma estrutura de métodos e propriedades do código. Pois geralmente as versão 2.x, 3.x, 4.x sempre mudam algo na estrutura.

Sinal ~ (Tilde)

O sinal ~ indica que o NPM pode atualizar a versão da dependência para qualquer versão que não altere o número menor do ponto decimal.

Sendo assim, ele permite atualizações como: 1.2.x, mas não 1.3.0 ou superior.

Por exemplo, se a dependência estiver especificada como ~1.2.3, o NPM instalará a versão mais recente que é 1.2.x onde o x pode ser qualquer valor, mas não versões 1.3.0 ou superiores.

"dependencies": {
  "another-package": "~1.2.3"
}

Permitindo atualizações sem restrições

Se você deseja que o NPM instale sempre a versão mais recente de uma dependência dentro de uma faixa principal específica, como qualquer versão 2.x.x ou 3.x.x, você pode usar a versão "sem restrições" ou configurar o versionamento no package.json para refletir isso. 

Vejamos alguns exemplos:

"dependencies": {
  "puppeteer": "23.2.0"
}

No caso do exemplo acima, como não especificamos nenhuma restrição, o NPM vai buscar sempre a versão que foi especificada na época, que é a 23.2.0.

"dependencies": {
  "puppeteer": ">=23.2.0"
}

O símbolo de maior ou igual (>=), permite que seja instalado a partir da versão 23.2.0 ou superior, e isso inclui 24.x, 25.x e por ai vai.

Mas cuidado ao fazer isso, pois qualquer atualização de pacote, poderá causar incompatibilidade com seu código.

"dependencies": {
  "example-package": ">=2.0.0 <4.0.0"
}

">=2.0.0 <4.0.0" permitirá qualquer versão a partir de 2.0.0 até, mas não incluindo, 4.0.0 seja aceita. Isso garante que você receba qualquer versão dentro da faixa 2.x.x e 3.x.x.

Lembrando que você pode usar o <= alí também, o que permite a versões menores ou iguais a 4.x.x mais não superiores a ela.

Instalando versões específicas com NPM

Você também pode escolher a versão do pacote que você deseja instalar no seu projeto, e isso pode ser feito de duas formas diferentes:

  • npm install <nome-do-pacote>@1.0.0
  • npm install <nome-do-pacote>@latest

O primeiro comando (@1.0.0) procura e instala a versão 1.0.0, já o segundo comando (@latest) busca pela versão mais nova disponível.

Importando um pacote para dentro do seu projeto em NodeJS

Após a instalação dos seus pacotes na pasta do seu projeto, basta que você use o require dentro do seu index.js da seguinte forma:

const pacote = require('nome-do-pacote');

Lembrando que cada pacote possui uma documentação diferente, logo, cada pacote possui métodos e propriedades diferentes 😉

Chencando atualizações de pacotes

Para verificar os pacotes que necessitam de uma atualização, podemos usar o seguinte comando:

npx npm-check-updates -u

O npx é um utilitário incluído com o NPM que permite executar pacotes NodeJS diretamente sem precisar instalá-los globalmente. Ele procura o pacote no repositório do NPM, o baixa (se necessário) e o executa.

npm-check-updates, é um comando do NPM que busca e lista todas as atualizações de pacotes que já existem dentro do package.json.

Por fim, temos a tag -u, que instrui o npm-check-updates a atualizar o arquivo package.json com as versões mais recentes das dependências, substituindo as versões atuais por essas versões mais novas.

Atualizando todos os pacotes

Com o NPM, você pode atualizar todos os pacotes instalados. Para isso, com o terminal (Prompt de Comando) aberto dentro da pasta raiz do seu projeto, execute o comando:

npm update

Ele verifica o package.json e o package-lock.json, de modo a atualizar os pacotes instalados para as versões mais recentes que respeitam as faixas de versão especificadas (>, <, ^, ~, =).

Observação: Você também pode usar o comando npm install para atualizar todos os pacotes.

Atualizando um pacote específico

Para atualizar um pacote específico, você pode usar o seguinte comando:

npm update <nome-do-pacote>

Esse comando atualiza apenas o pacote especificado para a versão mais recente permitida pelas restrições (><^~=) de versão no package.json.

Atualizando um pacote para a última versão disponível

Se você deseja atualizar um pacote para a versão mais recente disponível, independentemente das restrições  (><^~=) de versão especificadas no package.json, você pode usar o seguinte comando:

npm install <nome-do-pacote>@latest

O @latest força a instalação da versão mais recente do pacote, e atualizará o package.json e package-lock.json para refletir essa versão.

Checando os pacotes que precisam ser atualizados

O NPM possui um comando chamado de outdated, que visa listar todos os pacotes instalados na pasta do seu projeto, e que precisam de uma atualização:

npm outdated

Note que no caso da ilustração acima, foi identificado que um pacote possui uma versão mais recente.

Observação: Com o comando npm update, você pode atualizar não só esse pacote, mas como todos os outros que também precisam ser atualizados.

Removendo um pacote

Para remover um pacote que está listado em seu package.json e na pasta node_modules, você pode usar o comando

npm uninstall <nome-do-pacote>

Com o uninstall, o NPM removerá o seu pacote tanto da pasta node_modules, quantos dos arquivo package.json e package-lock.json.

Removendo todos os pacotes

Para remover todos os pacotes, o processo segue de forma manual 🥲

1° Passo) Remova a pasta node_modules e package-lock.json.

2° Passo) Dentro do package.json remova as chaves das dependências da seguinte forma:

{
  "name": "seu-projeto",
  "version": "1.0.0",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  }
  // Remova as seções dependencies e devDependencies
}

E não se esqueça de limpar o cache do NPM depois de uma limpeza, ou atualização:

npm cache clean --force

Usando o npm install em conjunto com as flags

Quando você usa o comando npm install <pacote>, há várias flags que você pode utilizar para controlar o comportamento da instalação.

Veremos nos próximos tópicos, cada uma delas 😌

-g ou --global

Instala o pacote globalmente em vez de localmente. Pacotes instalados globalmente ficam disponíveis em qualquer lugar no sistema.

npm install -g typescript

Lembrando que você pode executar um require normalmente como se o pacote estivesse instalado na pasta node_modules, essa estratégia vai funcionar, pois o NodeJS é inteligente o suficiente para não só buscar na pasta do projeto, como buscar de forma global, isto é, caso o pacote tenha sido instalado de forma global.

Para remover um módulo que você instalou globalmente, basta utilizar o seguinte comando:

npm remove <nome-do-pacote> -g

Não se esqueça de informar os comandos remove e -g, para que o NPM saiba que o pacote que você quer remover está instalado de forma global 😉

--save

Adiciona o pacote à seção dependencies do package.json.

É importante ressaltar que essa flag é implícita nas versões mais recentes do NPM, e não precisa mais ser usada explicitamente.

npm install <nome-do-pacote> --save

Isso significa dizer que, quando utilizamos o comando npm install <nome-do-pacote>, por de baixo dos panos, o NPM já está salvando esse pacote, ou seja, ele já usa a flag --save.

--save-dev

Adiciona o pacote à seção devDependencies do package.json.

Há uma possibilidade de instalar pacotes que só irão ser executados apenas no ambiente de desenvolvimento, e para isso usamos a flag --save-dev:

npm install <nome-do-pacote> --save-dev

Dentro do package.json, ele fica em uma seção totalmente separado dos demais.

Isso ajuda durante a build de produção, pois nesse caso específico, o NPM não vai baixar esses pacotes no servidor online (servidor de produção).

Um grande exemplo disso, são alguns testes unitários que não precisam estar no servidor de produção, e também o caso do Nodemon, em que usamos o PM2 para isso.

--save-peer

Adiciona o pacote à seção peerDependencies do package.json.

npm install <nome-do-pacote> --save-peer

--save-optional

Adiciona o pacote à seção optionalDependencies do package.json.

npm install <nome-do-pacote> --save-optional

--no-save

Instala o pacote sem atualizar o package.json ou o package-lock.json.

npm install <nome-do-pacote> --no-save

O comando --no-save no contexto do NPM é usado para instalar pacotes sem salvar a referência no arquivo package.json.

Isso significa que o pacote será instalado apenas na pasta node_modules do seu projeto, e não será adicionado às dependências do seu projeto no package.json.

Sendo assim, se algum dia você compartilhar o package.json com alguém, 

--legacy-peer-deps

Ignora as peerDependencies e instala o pacote mesmo se houver conflitos de versão, o que se torna bem útil quando há problemas com dependências peer conflitantes.

npm install <nome-do-pacote> --legacy-peer-deps

--strict-peer-deps

Garante que a instalação falhe se houver conflitos de peerDependencies, forçando uma resolução mais rigorosa.

npm install <nome-do-pacote> --strict-peer-deps

--no-optional

Não instala as dependências marcadas como optionalDependencies no package.json.

npm install --no-optional

--production

Instala apenas as dependências listadas em dependencies, ignorando devDependencies e optionalDependencies. Útil para ambientes de produção.

npm install --production

--dry-run

Simula a instalação sem realmente modificar o sistema de arquivos. Útil para ver o que seria instalado antes de executar a instalação real.

npm install <nome-do-pacote> --dry-run

--verbose

Fornece informações mais detalhadas durante a instalação. Útil para depuração.

npm install <nome-do-pacote> --verbose

--prefix

Instala pacotes em um diretório específico em vez do diretório atual. É útil para configurar projetos em locais não padrão.

npm install <nome-do-pacote> --prefix /path/to/directory

--no-audit

Desativa a auditoria de segurança que normalmente é realizada após a instalação.

npm install <nome-do-pacote> --no-audit

--audit-level

Define o nível de severidade para a auditoria de segurança. Pode ser low, moderate, high ou critical.

npm install <nome-do-pacote> --audit-level=high

--cache

Define um diretório de cache personalizado para o npm usar durante a instalação.

npm install <nome-do-pacote> --cache /path/to/cache

Usando flags de forma combinada

Você pode combinar várias dessas flags para ajustar o comportamento da instalação.

Por exemplo, vamos supor que você queira instalar um pacote globalmente, sem atualizar o package.json, você poderia usar o comando:

npm install -g <nome-do-pacote> --no-save

Criando seus próprios scripts por meio do NPM

Talvez você deve ter imaginado, quando aprendeu o funcionamento da chave "scripts" do package.json, a seguinte situação: Será que é possível adicionar meus próprios scripts personalizados?

E a resposta é SIM, você PODE! 🤩

Graças a chave "scripts" do arquivo package.json, você pode executar uma série de comandos, digitando apenas um ÚNICO comando.

Para exemplificar isso, vamos supor que você deseja executar o comando node ./index.js informando apenas start no terminal, você pode fazer isso da seguinte forma:

"scripts": {
  "test": "echo \"Error: no test specified\" && exit 1",
  "start": "node ./index.js"
},

Note que eu adicionei uma nova chave chamada start dentro de scripts, que possui um comando em NodeJS.

No terminal, basta executar o comando: npm start, que por de baixo dos panos, é como se tivéssemos executado o node ./index.js.

Qual a linguagem usada dentro de scripts do NPM?

A linguagem utilizada é essencialmente a shell scripting (ou script de shell), e isso significa que você pode escrever comandos que são executados pelo shell do seu sistema operacional.

Como é o caso do Bash no Linux e macOS, ou quem sabe o Command Prompt/Powershell no Windows, tudo vai depender do sistema operacional que o seu projeto estiver rodando.

Observação: Existem algumas chaves dentro de "scripts" que só são executadas em conjunto com o run, como por exemplo:

"scripts": {
  "test": "echo \"Error: no test specified\" && exit 1",
  "start": "node ./index.js"
  "micilini": "...."
},

...

npm start //Funciona!
npm run start //Funciona!
npm micilini // Não funciona!
npm run micilini //Funciona!

Vale lembrar que o comando npm start é uma exceção especial no NPM. (assim como o npm test).

Quando você define um script com a chave "start" no seu package.json, o NPM permite que você execute esse script simplesmente com npm start sem precisar usar o npm run start explicitamente (apesar de que o uso do comando npm run start, também funciona).

E como a chave "micilini" não faz parte de nenhuma exceção, nos vemos obrigados a executar o comando: npm run micilini. (Se você tivesse uma outra chave chamada "roll", você ainda precisaria usar o npm run roll...)

Além disso, você pode retornar no seu terminal todos os scripts suportados pelo seu projeto, para isso basta executar o comando abaixo:

npm run

Pacotes Executáveis (npx)

Alguns pacotes nem sempre vão precisar do uso do comando require dentro do seu arquivo Javascript, uma vez que se tratam de scripts executáveis, e que resultam em alguma ação do nosso computador.

Um grande exemplo disso, são os pacotes: Nodemon, React, ESLint, Mocha, Prettier e entre outros... Onde alguns deles podem ser executados de forma global usando apenas a linha de comando (prompt).

Vamos pegar como exemplo, o pacote do React que é executado pelo comando npx:

npx create-react-app <nome-do-projeto>

Se você acompanhou a Jornada ReactJS aqui no Portal da Micilini, sabe que o comando acima, cria um novo projeto com ReactJS contendo toda a estrutura de arquivo.

Portanto, no caso do npx create-react-app, temos uma série de processos que são simplificados, incluindo a própria criação dos arquivos package.json.

Apesar disso, os projetos feitos em React ainda precisam ser executados com npm start.

NPM vs NPX

O NPM (Node Package Manager) é o gerenciador de pacotes padrão para NodeJS, cujo o principal objetivo é instalar, atualizar, remover e gerenciar pacotes do NodeJS e suas dependências.

Já o NPX (Node Package Execute) é uma ferramenta que vem com o NPM, e é usada para executar pacotes NodeJS que não estão necessariamente instalados no projeto ou no sistema.

Se tornando útil para executar ferramentas e utilitários sem a necessidade de instalá-los globalmente ou como dependências do projeto.

No caso do NPM, podemos dizer que:

  • Foca na instalação e gerenciamento de pacotes, seja localmente ou globalmente.
  • Instala pacotes que são adicionados ao package.json ou ao sistema.
  • Permite controlar as versões de pacotes no package.json e usa as versões especificadas para instalações.

No caso do NPX:

  • Foca na execução de pacotes e scripts sem a necessidade de instalação permanente.
  • Executa pacotes diretamente sem adicioná-los ao package.json ou instalar globalmente.
  • Executa a versão mais recente do pacote disponível, a menos que uma versão específica seja fornecida.

Resumindo, o NPM é usado para gerenciar pacotes que são utilizados diretamente no projeto (require), ou seja, dentro dos arquivos Javascript. Já o NPX é usado para instalar pacotes que não estão ligados diretamente ao projeto em sí, mas que apoiam o mesmo!

Alterando configurações do NPM

Podemos utilizar o comando npm config set, para configurar certas opções, de modo a definir valores específicos para a configuração do nosso gerenciador.

Isso vai permitir que o comportamento do NPM possa ser ajustado de acordo com as nossas necessidades, e preferências individuais.

E não, o comando que iremos aprender agora, não tem nada haver com o package.json, mas sim as configurações do próprio NPM que esta instalado na sua máquina, ok?

A sintaxe básica da útilização do NPM é esta:

npm config set <key> <value>

<key>: é a chave de configuração que você deseja definir.

<value>: é o valor que você deseja atribuir à chave de configuração.

Vamos ver alguns exemplos da sua utilização abaixo 😉

Alterando as preferências de usuário

Você pode usar o comando init-author-name, para deixar pré-configurado o nome do autor do projeto, sempre que você for usar o comando npm init.

npm config set init-author-name "Seu Nome"

Isso fará com que da próxima vez que você execute um novo projeto usando npm init, o nome do autor já venha preenchido com o nome que você escolheu.

Você pode recuperar o nome escolhido usando o comando get da seguinte forma:

npm config get init-author-name

O comando acima irá retornar o nome do autor que está setado de forma padrão no NPM.

Para retornar todas as configurações de uma só vez, utilize o comando:

npm get

Para remover o valor padrão, basta utilizar o comando delete da seguinte forma:

npm config delete init-author-name

Lembrando que a mesma coisa pode ser feita com os comandos de configuração que iremos aprender abaixo:

init-author-name: nome do autor padrão a ser usado em novos pacotes.

npm config set init-author-name "Seu Nome"

init-author-email: email do autor padrão a ser usado em novos pacotes.

npm config set init-author-email "seuemail@example.com"

init-author-url: URL do autor padrão a ser usada em novos pacotes.

npm config set init-author-url "https://seusite.com"

init-license: licença padrão a ser usada em novos pacotes. Por exemplo, MIT.

npm config set init-license "MIT"

init-version: versão padrão inicial do pacote. Geralmente, 1.0.0.

npm config set init-version "1.0.0"

init-description: descrição padrão a ser usada em novos pacotes.

npm config set init-description "Descrição padrão do pacote"

init-main: arquivo principal padrão para o pacote. Por exemplo, index.js.

npm config set init-main "index.js"

init-scripts: scripts padrão para o pacote. Esses podem incluir test, start, etc.

npm config set init-scripts '{"test": "echo \"Error: no test specified\" && exit 1"}'

init-keywords: palavras-chave padrão para o pacote.

npm config set init-keywords "keyword1, keyword2"

Lembrando que:

  • Usamos o comando set para setar um valor (npm config set <key> <value>)
  • Usamos o comando get para recuperar e consultar um valor (npm config get <key>)
  • Usamos o comando delete para remover o valor padrão (npm config delete <key>)

Para consultar a documentação completa com todas as configurações do NPM, acesse este link.

Listando os pacotes instalados

Por meio do terminal (Prompt de Comando), é possível analisarmos cada pacote que está instalado na pasta do nosso projeto, isso tanto globalmente, quanto os pacotes que estão instalados no projeto.

Para fazer este tipo de verificação, dentro da pasta do seu projeto, você pode verificar os pacotes instalados por meio do seguinte comando:

npm list

O list irá listar todos os pacotes que estão instalados na pasta do seu projeto:

Você pode esconder algumas partes da sua arvore de pacotes usando a flag --depth=0:

npm list --depth=0

Sendo que o 0 pode ser alterado para 1, 2, 3 e etc... quanto maior for o número, maior será a arvore de pacotes dependentes que será mostrado no prompt.

Agora, para listarmos as dependências que estão instaladas globalmente, basta usar a flag -g da seguinte forma:

npm list -g

Lembrando que você pode usar a flag --depth em conjunto com a -g😋

Limpando dependências não utilizadas no seu projeto

Exitirão momentos em que você vai desejar fazer uma limpeza nas dependências do seu projeto.

Pensando nisso, a equipe do NPM desenvolveu uma nova funcionalidade capaz de remover todos os pacotes que não estão sendo utilizados no seu projeto de forma automática.

Para isso, a primeira coisa que você precisa fazer é: Abrir o package.json, e ir removendo manualmente, os pacotes que você não precisa mais:

Em seguida, basta abrir o terminal (Prompt de Comando) na pasta raiz do seu projeto e executar:

npm prune

O prune vai abrir o seu package.json, recuperar todos os pacotes alí presentes, e vai comprar com os pacotes existentes dentro da pasta node_modules. Afim de remover todos os pacotes que não estão listados no seu arquivo JSON.

Ele abstrai o fato de termos que remover manualmente a pasta de cada pacote existente dentro de node_modules, o que faz com que a gente ganhe um pouco de tempo no desenvolvimento.

Realizando uma busca de pacotes no NPM diretamente pelo terminal

O gerenciador NPM é tão completo, que ele abstrai o fato de precisarmos entrar na página principal deles para buscar por um determinado pacote 😯

Usando o terminal (Prompt de Comando), você é capaz de realizar uma busca pelos pacotes existentes no NPM, para isso basta usar o comando search da seguinte forma:

npm search <nome-do-pacote>

No comando acima, nos foi retornado todos os pacotes que levam a keyword cpf. (alí usamos o comando npm searc cpf)

Veja quantos pacotes que trabalham com CPF, e que podemos usar no nosso projeto, muitos, não? 🤩

Você pode fazer o uso das aspas duplas para que o NPM entenda que você está buscando por um pacote só (em vez de dois):

npm search "react test"

Analisando e limpando o cache do NPM

O NPM possui um comando chamado de npm cache verify, que é útil para  examinar o cache do próprio NPM, de modo a verificar se o mesmo está íntegro e não corrompido.

npm cache verify

E sim, durante a movimentação dos arquivos do seu projeto, muita coisa pode ser corrompida, ou até mesmo perdida 😱

Este comando, gera um relatório sobre o estado do cache, incluindo informações sobre o tamanho do cache, e quaisquer problemas encontrados, como arquivos corrompidos ou inconsistentes.

Se encontrar problemas, o comando npm cache verify pode corrigir automaticamente alguns deles, removendo arquivos corrompidos e liberando espaço.

Para termos a certeza que o cache foi apagado, você pode utilizar o comando:

npm cache clean --force

A flag --force vai forçar uma limpeza de cache por parte do NPM, use com cautela!

Identificando vulnerabilidades nos pacotes do nosso projeto

Durante a sua jornada como desenvolvedor, durante alguns momentos, você irá se deparar com as seguintes mensagens de alerta:

Alegando que foram encontradas uma ou mais vulnerabilidades nos pacotes de terceiros 😱

E a primeira pergunta que sempre vem a mente é: Será que eu devo me preocupar?

Antes de responder a essa pergunta, você precisa entender que nem todo criador de um pacote, possui todos os conhecimentos necessários para deixá-lo seguro.

E além disso, 95% dos pacotes possuem algum tipo de vulnerabilidade, comumente classificada como baixa (low) ou mediana (medium).

Isso significa dizer que é muuuuuito raro termos um projeto sem nenhum tipo de vulnerabilidade. As vezes, o NPM classifica um pacote como vulneravél, sendo que ele não é tão vulnerável assim.

Com relação as vulnerabilidades do tipo baixa ou media, você não precisa se preocupar muito. Agora vulnerabilidades do tipo Alta (High) já merecem seu ponto de atenção!

Além disso, é importante que você saiba, que nem sempre o criador do pacote vai ter tempo para corrigir essa vulnerabilidade, o que implica na mudança do próprio pacote em sí, ou seja, deixar de usá-lo para usar um outro mais seguro 😉

Agora, iremos aprender um comando específico do NPM capaz de detectar falhas de segurança em cada um dos nossos pacotes:

npm audit

Com este comando, o NPM nos retornará um relatorio bem detalhado das possíveis falhas de segurança existente em cada um dos nossos pacotes.

Observação: É super importante que você (desenvolvedor), fique checando de tempo em tempos, possíveis problemas de vulnerabilidade relacionado com os pacotes de terceiros.

Para corrigir as vulnerabilidades, basta usar o comando fix em conjunto com o comando npm audit:

npm audit fix

O comando fix, ajusta tudo o que for necessário para corrigir os problemas de vulnerabilidade nos pacotes de terceiros.

Mas lembre-se que nem sempre ele consegue corrigir, ok? Isso se deve ao fato de algumas restrições do próprio NPM e também a falta de versões recentes dos pacotes de terceiros.

Existem algumas correções de vulnerabilidades, em que o NPM não consegue realizar a correção, pois existem grandes chances de quebrar o seu projeto.

Em casos assim, como uma última alternativa, você pode usar a flag --force, para forçar uma correção:

npm audit fix --force

NPM View

O gerenciador de pacotes (NPM), possui uma funcionalidade muito interessante chamada de view.

Seu objetivo é colher o máximo de informações relacionadas a um determinado pacote (esteja ele instalado na nossa máquina local, ou não).

Para utilizá-lo é bem simples, basta digitar o comando abaixo no terminal:

npm view

Note que temos diversas informações, desde as versões de distribuição, mantenedores, versões legadas, últimas, alpha, beta e entre outras.

Para instalar uma determinada versão, você pode utilizar os comandos abaixo, logo após o nome do pacote (como já vimos antes):

  • @latest
  • @alpha
  • @csp
  • @v2-latest
  • @legacy
  • E entre outras....

Por exemplo:

npm install <nome-do-pacote>@latest
npm install <nome-do-pacote>@alpha
npm install <nome-do-pacote>@csp
npm install <nome-do-pacote>@v2-latest
npm install <nome-do-pacote>@legacy

Reduzindo pacotes duplicados

Algumas bibliotecas podem depender de uma mesma biblioteca em comum. O que ocasiona uma duplicação de bibliotecas na pasta do seu projeto.

Por exemplo, o pacote A depende do pacote C versão 1.0.0, e o pacote B também depende do pacote C, só que a versão 1.3.7.

Concorda comigo que o pacote C está duplicado dentro do nosso projeto?

E apesar de ambos os pacotes estarem fazendo o uso de versões diferentes, ainda assim, o pacote C está duplicado?

Sim, se você se aventurar nas pastas do node_modules, verá que existirão duas versões do pacote C 😅

Pensando em resolver essa questão, a equipe de desenvolvimento do NPM lançou uma funcionalidade chamada de dedupe (você também pode usar apenas ddp) que pode ser usada de ambas as formas:

npm dedupe
npm ddp

Com ele, nós podemos realizar uma pesquisa na árvore de pacotes local, na tentativa de simplificar a estrutura geral, movendo as dependências para cima na árvore, onde elas possam ser compartilhadas de forma mais eficaz por vários pacotes dependentes.

No final, o resultado ficaria igual a ilustração abaixo:

Ou seja, o comando npm dedupe, pega a versão mais recente do pacote duplicado, extrai ele para uma pasta superior, e faz referência a ele nos pacotes que os utiliza.

Observação: o npm dedupe, não reduz pacotes com versão muito diferentes, por exemplo: 1.3.7 e 2.0.5, pois ele entende que dá versão 1x para 2x, muita coisa pode ser alterada, e que uma possível mudança afetaria o bom funcionamento do seu projeto.

Conclusão

Nossaaa, que conteúdo denso, heim? 🥸

Nesta lição você aprendeu bastante coisas relacionadas ao gerenciador NPM 🥳

Vimos desde os conceitos básicos, até comandos mais avançados que não são muito utilizados no dia a dia.

Fique a vontade para consultar essa lição sempre que desejar, e até a próxima 🤩

Criadores de Conteúdo

Foto do William Lima
William Lima
Fundador da Micilini

Inventor nato, escreve conteudos de programação para o portal da micilini.

Torne-se um MIC 🤖

Mais de 100 mic's já estão conectados na plataforma.