In this article
Os 10 principais comandos avançados do npm que todo desenvolvedor JavaScript deve conhecer
Comandos avançados podem simplificar tarefas complexas e oferecer uma visão mais aprofundada das dependências e configurações do seu projeto. De identificar vulnerabilidades a gerar uma lista de materiais de software (SBOM), esses comandos vão ajudar você a ser um desenvolvedor mais eficiente e atento à segurança.
O gerenciador de pacotes npm é uma ferramenta indispensável no ecossistema JavaScript e Node.js. Ele é a base para gerenciar dependências, scripts e configurações que agilizam os fluxos de trabalho de desenvolvimento. Seja para criar um projeto pequeno ou uma aplicação em grande escala, dominar os comandos do npm pode aumentar significativamente sua produtividade e a qualidade do código.
Snyk para projetos JavaScript seguros
A segurança é um aspecto essencial do desenvolvimento de software moderno. A Snyk se integra perfeitamente ao seu fluxo de trabalho de desenvolvimento em JavaScript para detectar vulnerabilidades no código-fonte, em pacotes de código aberto, imagens de contêineres e configurações de nuvem.
Ao conhecer estes comandos avançados do npm power-user, considere reforçar sua postura de segurança criando uma conta gratuita na Snyk.
1. Encaminhar opções da linha de comando para scripts do npm run com --
Em projetos complexos, muitas vezes você precisa passar opções adicionais da linha de comando para scripts executados por meio de npm run. Isso é especialmente útil quando você quer ajustar o comportamento de um script sem modificá-lo. Por exemplo, você pode querer alterar o ambiente dinamicamente, ativar a depuração ou passar opções de configuração.
Exemplo de uso em um script do npm run
Para encaminhar opções da linha de comando ao programa executado por um script npm run, use a sintaxe de dois hífens --. Tudo o que vier depois de -- será passado diretamente ao script.
Veja um exemplo básico:
{
"scripts": {
"start": "node app.js"
}
}
Você pode executar o script start e passar opções adicionais ao programa app.js da seguinte maneira:
npm run start -- --port=3000 --env=productionNesse caso, --port=3000 e --env=production são encaminhados ao script app.js como argumentos posicionais.
Considerações de segurança
Passar opções dinamicamente pode ser muito útil, mas também traz possíveis riscos de segurança. Verifique se os scripts e as opções que você passa são seguros e não expõem informações confidenciais nem permitem comportamentos indesejados. Sempre valide e higienize as entradas ao lidar com opções dinâmicas.
2. Inspecionar árvores de dependências com npm ls
Como desenvolvedor JavaScript, você precisa entender a árvore de dependências do seu projeto para identificar quais pacotes são afetados por vulnerabilidades. O comando npm ls é um dos comandos avançados que ajudam a inspecionar essa árvore. Ele mostra uma representação em árvore ASCII de todos os pacotes dos quais seu projeto depende, incluindo versões e relações hierárquicas.
Sintaxe do comando npm ls e opções de filtragem
A sintaxe básica do comando npm ls é:
npm ls [<package-name>]Esse comando pode listar todas as dependências ou se concentrar em um pacote específico, caso você informe o nome dele. Além disso, você pode filtrar a saída para mostrar apenas dependências de produção ou de desenvolvimento usando, respectivamente, as opções --production ou --development.
Exemplo de como encontrar dependências afetadas por uma vulnerabilidade específica
Imagine que você descobriu uma vulnerabilidade de negação de serviço no pacote ms npm. Para identificar quais dependências do seu projeto são afetadas por essa versão vulnerável, use o comando npm ls:
Esse comando exibirá a árvore de dependências e destacará onde ms é usado. Veja um exemplo da saída:
> npm ls ms
goof@1.0.1 /Users/lirantal/projects/repos/nodejs-goof
├─┬ express-session@1.17.2
│ └─┬ debug@2.6.9
│ └── ms@2.0.0
├─┬ express@4.12.4
│ ├─┬ debug@2.2.0
│ │ └── ms@0.7.1
│ ├─┬ finalhandler@0.3.6
│ │ └─┬ debug@2.2.0
│ │ └── ms@0.7.1
│ └─┬ send@0.12.3
│ ├─┬ debug@2.2.0
│ │ └── ms@0.7.1 deduped
│ └── ms@0.7.1
├─┬ humanize-ms@1.0.1
│ └── ms@0.6.2
├─┬ method-override@3.0.0
│ └─┬ debug@3.1.0
│ └── ms@2.0.0
├─┬ mongoose@4.2.4
│ ├─┬ mquery@1.6.3
│ │ └─┬ debug@2.2.0
│ │ └── ms@0.7.1
│ └── ms@0.7.1
├─┬ morgan@1.10.0
│ └─┬ debug@2.6.9
│ └── ms@2.0.0Você também pode pesquisar especificamente por ms@0.7.1.
3. Entender dependências transitivas com npm why
Em projetos JavaScript grandes, gerenciar dependências pode ser complexo, especialmente quando há dependências transitivas — aquelas que não estão incluídas diretamente no seu package.json, mas são necessárias para suas dependências diretas.
Identificar por que determinado pacote está incluído no seu projeto pode ser essencial para depurar e proteger sua aplicação. O comando npm why ajuda nisso, fornecendo informações detalhadas sobre por que um pacote específico está instalado.
O comando npm why é simples de usar. A sintaxe básica é:
> npm why ms@0.7.1
ms@0.7.1
node_modules/send/node_modules/ms
ms@"0.7.1" from send@0.12.3
node_modules/send
send@"0.12.3" from express@4.12.4
node_modules/express
express@"4.12.4" from the root project
send@"0.12.3" from serve-static@1.9.3
node_modules/serve-static
serve-static@"~1.9.3" from express@4.12.4
node_modules/express
express@"4.12.4" from the root project
ms@"0.7.1" from debug@2.2.0
node_modules/send/node_modules/debug
debug@"~2.2.0" from send@0.12.3
node_modules/send
send@"0.12.3" from express@4.12.4
node_modules/express
express@"4.12.4" from the root project
send@"0.12.3" from serve-static@1.9.3
node_modules/serve-static
serve-static@"~1.9.3" from express@4.12.4
node_modules/express
express@"4.12.4" from the root projectComo você pode ver, esse comando do npm exibirá uma explicação detalhada do motivo pelo qual ms está incluído, mostrando a cadeia de dependências que levou à instalação.
Dicas extras para o comando npm why
Especifique a versão: se você souber qual versão está causando problemas, inclua-a no comando para obter resultados mais precisos:
npm why ms@0.7.1Use a saída JSON: para obter uma saída mais completa e detalhada, que inclua tipos de dependência e outros metadados, use a opção
--json:
npm why ms@0.7.1 --jsonIsso pode ser especialmente útil para scripts automatizados ou análises mais aprofundadas.
Entender as dependências transitivas é essencial para manter uma base de código segura e eficiente. Ferramentas como o Snyk Open Source também podem ajudar, analisando suas dependências em busca de vulnerabilidades conhecidas e oferecendo informações práticas para agir. Crie uma conta gratuita na Snyk e proteja seus projetos hoje mesmo.
Se você está começando a gerenciar dependências e quer entender como os arquivos de bloqueio funcionam, outro recurso útil é o artigo “O que é o package-lock.json e como funciona um arquivo de bloqueio para pacotes yarn e npm?”. O artigo explica o versionamento semântico, arquivos de bloqueio shrinkwrap, arquivos de bloqueio desatualizados e outros conceitos importantes sobre arquivos de bloqueio do npm.
4. Listar scripts de ciclo de vida disponíveis com npm run
Ao trabalhar em um projeto JavaScript ou Node.js, muitas vezes você precisa executar vários scripts definidos no arquivo package.json, certo? Alguns exemplos comuns são npm run test e npm run build.
Mas pode ser difícil lembrar os nomes exatos de todos esses scripts de ciclo de vida do npm lifecycle, especialmente em projetos maiores ou quando você trabalha regularmente em vários projetos, como os de back-end e front-end.
O comando npm run vem ao resgate! Ele resolve esse problema listando todos os scripts de ciclo de vida disponíveis no seu projeto, para você ver facilmente quais são e como executá-los.
Veja um exemplo prático de como consultar todos os scripts npm run de um projeto:
> npm run
Lifecycle scripts included in goof@1.0.1:
start
NODE_OPTIONS=--openssl-legacy-provider node app.js
test
snyk test
available via `npm run-script`:
dev
NODE_OPTIONS=--openssl-legacy-provider nodemon ./app.js
build
browserify -r jquery > public/js/bundle.js
cleanup
mongo express-todo --eval 'db.todos.remove({});'A saída lista todos os scripts npm run disponíveis no projeto e os comandos que eles executam. Assim, você economiza alguns segundos sem precisar abrir o arquivo package.json no seu IDE ou terminal!
5. Consultas avançadas de dependências com npm query
Talvez você ainda não conheça esse recurso do gerenciador de pacotes npm, que permite filtrar e selecionar dependências com base em seus atributos. Você pode precisar fazer isso para entender o impacto de uma dependência de terceiros ou executar ações direcionadas, mas encontrar a dependência certa do npm pode ser complicado.
Introduzido no npm@8, o comando npm query oferece uma maneira poderosa de fazer consultas avançadas de dependências usando uma linguagem de consulta. Com ele, você pode filtrar e selecionar dependências com base em seus atributos, facilitando o gerenciamento e a auditoria das dependências do seu projeto.
Como usar a sintaxe do npm query
A sintaxe do comando npm query é:
npm query "<query>"A parte mais complicada é a consulta. Ela usa uma linguagem própria (DSL), que aceita vários atributos e operadores para refinar a pesquisa. Por exemplo, você pode filtrar dependências com base nos scripts de ciclo de vida, nas versões ou em outros metadados disponíveis nos pacotes de terceiros.
Exemplo: encontrar dependências com um script postinstall do npm
Imagine que você queira encontrar todas as dependências do seu projeto que tenham um script postinstall. Isso pode ajudar a identificar pacotes que executam scripts durante a instalação, o que pode representar riscos de segurança ou afetar seu processo de build. Use a consulta a seguir:
npm query ":attr(scripts, [postinstall])"Esse comando retornará uma lista de dependências com um script postinstall definido no arquivo package.json .
A saída pode ser parecida com esta:
[
{
"name": "some-package",
"version": "1.0.0",
"scripts": {
"postinstall": "node setup.js"
}
}
]Neste exemplo, some-package tem um script postinstall que executa node setup.js. Essas informações podem ajudar você a auditar suas dependências em busca de possíveis riscos de segurança ou comportamentos indesejados.
Dica extra: use a ferramenta de segurança da cadeia de suprimentos de código aberto npq tool para identificar preventivamente scripts postinstall ou preinstall nas dependências que você pretende instalar, antes de instalá-las.
6. Comparar versões com npm diff
Entender as mudanças entre diferentes versões de um pacote é essencial para manter uma base de código segura e estável. Isso é útil quando você quer descobrir o que mudou entre duas versões de um pacote.
O comando npm diff ajuda a comparar duas versões de um pacote. Ele é especialmente útil para identificar possíveis problemas de segurança, recursos obsoletos, dependências alteradas ou mudanças significativas que possam afetar sua aplicação.
O comando npm diff é simples de usar e funciona de forma parecida com o comando git diff:
npm diff --diff=<package@version1> --diff=<package@version2>Imagine que você queira comparar as mudanças entre as versões 2.1.2 e 2.1.3 do pacote ms. Execute o seguinte comando:
npm diff --diff=ms@2.1.3 --diff=ms@2.1.2A saída mostrará as diferenças no código, de forma semelhante à saída do git diff:
diff --git a/index.js b/index.js
index v2.1.3..v2.1.2 100644
--- a/index.js
+++ b/index.js
@@ -23,7 +23,7 @@
* @api public
*/
-module.exports = function (val, options) {
+module.exports = function(val, options) {
options = options || {};
var type = typeof val;
if (type === 'string' && val.length > 0) {
diff --git a/package.json b/package.json
index v2.1.3..v2.1.2 100644
--- a/package.json
+++ b/package.json
@@ -1,8 +1,8 @@
{
"name": "ms",
- "version": "2.1.3",
+ "version": "2.1.2",
"description": "Tiny millisecond conversion utility",
- "repository": "vercel/ms",
+ "repository": "zeit/ms",
"main": "./index",
"files": [
"index.js"
@@ -28,11 +28,10 @@
},
"license": "MIT",
"devDependencies": {
- "eslint": "4.18.2",
+ "eslint": "4.12.1",
"expect.js": "0.3.1",
"husky": "0.14.3",
"lint-staged": "5.0.0",
- "mocha": "4.0.1",
- "prettier": "2.0.5"
+ "mocha": "4.0.1"
}
}
diff --git a/license.md b/license.md
index v2.1.3..v2.1.2 100644
--- a/license.md
+++ b/license.md
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2020 Vercel, Inc.
+Copyright (c) 2016 Zeit, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/readme.md b/readme.md
index v2.1.3..v2.1.2 100644
--- a/readme.md
+++ b/readme.md
@@ -1,6 +1,7 @@
# ms
-
+[](https://travis-ci.org/zeit/ms)
+[](https://spectrum.chat/zeit)
Use this package to easily convert various time formats to milliseconds.Agora você pode revisar as mudanças para garantir que elas não introduzam vulnerabilidades de segurança nem alterações incompatíveis.
7. Criar e analisar SBOMs com npm sbom
SBOM é a sigla em inglês para lista de materiais de software: uma lista detalhada de todos os componentes e dependências do seu software, como uma receita que enumera todos os ingredientes.
Essa transparência ajuda a identificar possíveis vulnerabilidades e garante a conformidade com diferentes padrões de segurança. Os SBOMs são especialmente importantes para a segurança da cadeia de suprimentos, pois conhecer os componentes do seu software é essencial para gerenciar riscos e garantir a confiança.
As equipes de segurança costumam usar SBOMs para garantir a conformidade com padrões e regulamentações do setor, como a Ordem Executiva de Cibersegurança.
Como usar npm sbom e integrar com a Snyk
O comando npm sbom gera um SBOM para seu projeto ou espaço de trabalho.
Ele é especialmente útil quando combinado com a Snyk, uma ferramenta de segurança para desenvolvedores que detecta vulnerabilidades no código-fonte, em pacotes de código aberto, imagens de contêineres e configurações de nuvem.
Você pode usar o npm como gerenciador de pacotes para gerar um SBOM com todas as dependências do projeto e, em seguida, enviar o resultado com a árvore completa de dependências à Snyk para análise de vulnerabilidades. E tudo isso diretamente pela CLI.
Veja a sintaxe básica para criar um SBOM no formato CycloneDX usando npm sbom:
npm sbom --sbom-format cyclonedx > sbom.cdx.jsonAgora, você pode analisar esse SBOM em busca de vulnerabilidades usando a Snyk:
snyk sbom test --experimental --file=sbom.cdx.jsonIsso gerará uma saída com as vulnerabilidades encontradas no SBOM, incluindo os níveis de gravidade, como neste exemplo:
× [HIGH] Regular Expression Denial of Service (ReDoS)
Introduced through: pkg:npm/negotiator@0.2.8
URL: https://security.snyk.io/vuln/npm:negotiator:20160616
× [HIGH] Uninitialized Memory Exposure
Introduced through: pkg:npm/npmconf@0.0.24
URL: https://security.snyk.io/vuln/npm:npmconf:20180512
× [HIGH] Prototype Override Protection Bypass
Introduced through: pkg:npm/qs@2.2.4
URL: https://security.snyk.io/vuln/npm:qs:20170213
× [CRITICAL] Incomplete List of Disallowed Inputs
Introduced through: pkg:npm/babel-traverse@6.26.0
URL: https://security.snyk.io/vuln/SNYK-JS-BABELTRAVERSE-5962463
× [CRITICAL] Prototype Pollution
Introduced through: pkg:npm/handlebars@4.0.11
URL: https://security.snyk.io/vuln/SNYK-JS-HANDLEBARS-534988
× [CRITICAL] Server-side Request Forgery (SSRF)
Introduced through: pkg:npm/parse-url@5.0.1
URL: https://security.snyk.io/vuln/SNYK-JS-PARSEURL-2936249
× [CRITICAL] Arbitrary File Write via Archive Extraction (Zip Slip)
Introduced through: pkg:npm/adm-zip@0.4.7
URL: https://security.snyk.io/vuln/npm:adm-zip:20180415
╭──────────────────────────────────────────────────────────────────────╮
│ Test summary │
│ Organization: a30b7399-4e0c-4f6e-ba84-b27e131db54c │
│ Test type: Software Bill of Materials │
│ Path: sbom.cdx.json │
│ │
│ Open issues: 148 [ 4 CRITICAL 64 HIGH 72 MEDIUM 8 LOW ] │
╰──────────────────────────────────────────────────────────────────────╯8. Fixar versões de dependências com overrides no package.json
Como você talvez já tenha percebido, o gerenciamento de dependências pode ser uma faca de dois gumes. Embora o npm facilite muito a inclusão e o gerenciamento de dependências, isso também significa que seu projeto pode ficar vulnerável a problemas de segurança causados por dependências transitivas.
Um problema significativo enfrentado pelos desenvolvedores é a introdução de vulnerabilidades ou alterações incompatíveis nessas dependências transitivas. Por exemplo, um pacote amplamente usado pode apresentar de repente uma vulnerabilidade ou uma mudança incompatível, afetando todo o seu projeto.
O npm oferece um recurso poderoso chamado overrides no arquivo package.json para reduzir esses riscos. Esse recurso permite fixar versões específicas de dependências diretas e transitivas, garantindo que seu projeto use apenas as versões em que você confia.
Um caso real em que os overrides foram indispensáveis ocorreu no incidente de segurança de protestware envolvendo os pacotes peacenotwar e node-ipc, em março de 2022, ajudando a reduzir os impactos para quem usava esses pacotes.
Como usar a configuração overrides no package.json
Para usar o recurso overrides, adicione uma seção overrides ao arquivo package.json. Nessa seção, você especifica quais versões das dependências devem ser usadas, independentemente do que estiver definido nos arquivos package.json das próprias dependências.
Veja um exemplo básico de uso de overrides:
{
"name": "your-project",
"version": "1.0.0",
"dependencies": {
"some-package": "^2.0.0"
},
"overrides": {
"node-ipc@>9.2.1 <10": "9.2.1",
"node-ipc@>10.1.0": "10.1.0"
}
}Neste exemplo:
O pacote
node-ipcé fixado na versão 9.2.1 para versões superiores a 9.2.1 e inferiores a 10.O pacote
node-ipcé fixado na versão 10.1.0 para versões superiores a 10.1.0.
Reforce a segurança com a Snyk
Embora fixar dependências possa ajudar a reduzir alguns riscos, isso não resolve tudo. É fundamental verificar regularmente se há vulnerabilidades no seu projeto. Uma ferramenta de segurança que prioriza quem desenvolve, como a Snyk, detecta o quanto antes casos de malware, protestware e vulnerabilidades em geral nas suas dependências e ajuda você a corrigi-los.
Para começar a usar a Snyk, crie uma conta gratuita aqui.
9. Desenvolvimento local de pacotes com npm install
Ao desenvolver pacotes npm localmente, muitas vezes você precisa testá-los em outro projeto. Se não souber que o npm oferece esse recurso nativamente, terá que publicar o pacote no registro npm, um processo trabalhoso e demorado, sobretudo quando você precisa fazer alterações frequentes.
O comando npm install <path-to-package-in-disk-directory> resolve esse problema: ele permite instalar e vincular pacotes locais diretamente do diretório de desenvolvimento. Isso cria um link simbólico para o diretório em disco onde você está desenvolvendo o pacote, possibilitando atualizações e testes sem precisar republicá-lo sempre (e sem precisar desinstalá-lo e instalá-lo novamente localmente, graças ao link simbólico).
Para usar esse comando, acesse o diretório raiz do projeto onde você quer instalar o pacote local. Em seguida, execute:
npm install /path/to/local/packageSubstitua /path/to/local/package pelo caminho real do diretório do seu pacote local. Esse comando cria um link simbólico entre o diretório node_module's do projeto e o diretório do pacote local.
Vantagens práticas de instalar pacotes localmente com npm
Atualizações imediatas: as alterações no pacote local aparecem instantaneamente no projeto, sem necessidade de republicá-lo.
Depuração simplificada: você pode depurar e testar seu pacote em tempo real, no contexto do projeto maior.
Fluxo de trabalho eficiente: simplifica o desenvolvimento ao reduzir o trabalho envolvido no versionamento e na publicação de pacotes.
10. Segurança e compatibilidade com a configuração .npmrc
O arquivo .npmrc é um arquivo de configuração do npm que permite personalizar o comportamento dos comandos npm. Ele é essencial para reforçar a segurança e a compatibilidade dos seus projetos Node.js. Ao configurar determinadas opções no arquivo .npmrc, você pode proteger seus projetos contra pacotes maliciosos e garantir que as dependências sejam compatíveis com versões específicas do runtime do Node.js.
Ignore scripts para reforçar a segurança
Uma das maneiras mais eficazes de proteger seu projeto contra pacotes nocivos e maliciosos é desativar a execução de scripts de ciclo de vida. Esses scripts podem executar comandos arbitrários durante a instalação, o que representa um risco à segurança.
Ao definir ignore-scripts=true no arquivo .npmrc, você impede a execução desses scripts:
# .npmrc
ignore-scripts=trueCom essa configuração, o npm não executa nenhum script preinstall, postinstall ou outro script de ciclo de vida, reduzindo o risco de executar código malicioso.
Compatibilidade com versões do runtime do Node.js
Outro aspecto importante para manter um projeto seguro e estável é garantir a compatibilidade com versões específicas do runtime do Node.js. Isso é especialmente útil se o projeto depender de versões antigas ou sem suporte do Node.js. Ao definir node-version no arquivo .npmrc, você instrui o npm a atualizar somente as dependências compatíveis com a versão especificada do Node.js:
# .npmrc
node-version=14.0.0Com essa configuração, o npm considera somente as dependências compatíveis com o intervalo de versões especificado do Node.js na configuração do arquivo de manifesto engines.
Próximos passos
Os comandos Power-user npm são úteis não só para gerenciar dependências, mas também para reforçar a segurança e a eficiência do seu fluxo de desenvolvimento.
Você também pode gostar destes outros artigos sobre Node.js:
As dez melhores práticas de segurança para npm para proteger seus projetos JavaScript.
Dez recursos modernos do runtime do Node.js para começar a usar em 2024
Dez melhores práticas para conteinerizar aplicações web Node.js com Docker
As melhores práticas de Brian Clark para criar um pacote npm moderno com foco em segurança.
Ferramenta gratuita para verificar código
Proteja seu código antes do próximo commit.