O autor do material, cuja tradução publicamos hoje, diz que um dos problemas com os quais os programadores precisam lidar é que seu código funciona para eles e gera erros para outra pessoa. Esse problema, talvez um dos mais comuns, surge devido ao fato de diferentes dependências que o programa usa estarem instaladas nos sistemas do criador e do usuário do programa. Para combater esse fenômeno, os chamados arquivos de bloqueio existem nos
gerenciadores de pacotes
yarn e
npm . Eles contêm informações sobre as versões exatas das dependências. O mecanismo é útil, mas se alguém estiver desenvolvendo um pacote que está planejado para ser publicado no npm, é melhor não usar arquivos de bloqueio. Este material é dedicado à história do porquê disso.

A coisa mais importante em poucas palavras
Os arquivos de bloqueio são extremamente úteis ao desenvolver aplicativos Node.js. como servidores da web. No entanto, se você estiver falando sobre a criação de uma biblioteca ou ferramenta de linha de comando com o objetivo de publicar no npm, precisará saber que os arquivos de bloqueio no npm não são publicados. Isso significa que, se esses arquivos forem usados durante o desenvolvimento, o criador do pacote npm e aqueles que usam esse pacote usarão versões diferentes das dependências.
O que é um arquivo de bloqueio?
O arquivo de bloqueio descreve a árvore de dependência completa na forma que foi adquirida durante o trabalho no projeto. Esta descrição também inclui dependências aninhadas. O arquivo contém informações sobre versões específicas dos pacotes usados. No gerenciador de pacotes npm, esses arquivos são chamados de
package-lock.json
, em yarn -
yarn.lock
. Nos dois gerenciadores, esses arquivos estão localizados na mesma pasta que o
package.json
.
Aqui está
package-lock.json
.
{ "name": "lockfile-demo", "version": "1.0.0", "lockfileVersion": 1, "requires": true, "dependencies": { "ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "requires": { "color-convert": "^1.9.0" } }, "chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" } } } }
Aqui está um arquivo
yarn.lock
exemplo. Ele não foi projetado como
package-lock.json
, mas contém dados semelhantes.
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. # yarn lockfile v1 ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== dependencies: color-convert "^1.9.0" chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== dependencies: ansi-styles "^3.2.1" escape-string-regexp "^1.0.5" supports-color "^5.3.0"
Ambos os arquivos contêm algumas informações críticas de dependência:
- A versão exata de cada dependência instalada.
- Informações de dependência para cada dependência.
- Informações sobre o pacote baixado, incluindo a soma de verificação usada para verificar a integridade do pacote.
Se todas as dependências estão listadas no arquivo de bloqueio, por que elas adicionam informações sobre elas ao
package.json
? Por que são necessários dois arquivos?
Comparação de package.json e arquivos de bloqueio
O objetivo do campo de
dependencies
do arquivo
package.json
é mostrar as dependências do projeto que devem ser instaladas para que funcionem corretamente. Mas isso não inclui informações sobre as dependências dessas dependências. As informações de dependência podem incluir versões exatas do pacote ou um determinado intervalo de versões especificado de acordo com as regras do
controle de
versão semântico . Ao usar a faixa de npm ou fio, a versão mais adequada da embalagem é selecionada.
Suponha que o comando
npm install
sido executado para instalar as dependências de um determinado projeto. Durante o processo de instalação, o npm pegou pacotes adequados. Se você executar esse comando novamente depois de um tempo e se novas versões de dependências forem lançadas durante esse período, pode acontecer que na segunda vez em que outras versões dos pacotes usadas no projeto sejam carregadas. Por exemplo, se você instalar uma dependência, como
twilio
, usando o
npm install twilio
, a seguinte entrada poderá aparecer na seção
dependencies
do arquivo
package.json
:
{ "dependencies": { "twilio": "^3.30.3" } }
Se você olhar para a
documentação de versão semântica do npm, poderá ver que o sinal
^
indica que qualquer versão do pacote é adequada, cujo número é maior ou igual a 3.30.3 e menor que 4.0.0. Como resultado, se não houver um arquivo de bloqueio no projeto e uma nova versão do pacote for lançada, o
npm install
ou
yarn install
instalará automaticamente essa nova versão do pacote. As informações em
package.json
não serão atualizadas. Ao usar arquivos de bloqueio, tudo parece diferente.
Se o npm ou o yarn encontrar o arquivo de bloqueio correspondente, eles instalarão pacotes com base nesse arquivo, e não no
package.json
. Isso é especialmente útil, por exemplo, ao usar sistemas de Integração Contínua (IC) em plataformas nas quais você precisa garantir operação uniforme de código e testes em um ambiente cujas características são conhecidas antecipadamente. Nesses casos, você pode usar comandos ou sinalizadores especiais ao chamar os gerenciadores de pacotes apropriados:
npm ci # , package-lock.json yarn install --frozen-lock-file # , yarn.lock,
Isso é extremamente útil se você estiver desenvolvendo um projeto como um aplicativo ou servidor da Web, pois em um ambiente de IC, é necessário simular o comportamento do usuário. Como resultado, se incluirmos um arquivo de bloqueio no repositório do projeto (por exemplo, criado usando ferramentas git), podemos ter certeza de que todo desenvolvedor, todo servidor, todo sistema de criação de código e todo ambiente de IC usam as mesmas versões dependências.
Por que não fazer o mesmo ao publicar bibliotecas ou outras ferramentas de software no registro npm? Antes de responder a essa pergunta, precisamos falar sobre como o processo de publicação de pacotes funciona.
Processo de Publicação de Pacotes
Alguns desenvolvedores acreditam que o que é publicado no npm é exatamente o que é armazenado no repositório git ou o que o projeto se transforma após a conclusão do trabalho nele. Este não é realmente o caso. Ao publicar um pacote, o npm descobre quais arquivos publicar, acessando a chave de
files
no arquivo
package.json
e no arquivo
.npmignore
. Se nada disso puder ser detectado, o arquivo
.gitignore
será usado. Além disso, alguns arquivos são sempre publicados e outros nunca. Você pode descobrir o que esses arquivos estão
aqui . Por exemplo, o npm sempre ignora a pasta
.git
.
Depois disso, o npm pega todos os arquivos apropriados e os
empacota em um arquivo
tarball
usando o comando
npm pack
. Se você quiser ver exatamente o que está compactado em um arquivo, execute o
npm pack --dry-run
na pasta do projeto e veja a lista de materiais no console.
Saída do comando Npm pack --dry-runO arquivo
tarball
resultante é então carregado no registro npm. Ao executar o
npm pack --dry-run
você pode prestar atenção ao fato de que, se houver um arquivo
package-lock.json
no projeto, ele não será incluído no arquivo tarball. Isso ocorre porque esse arquivo, de acordo com as
regras do npm, é sempre ignorado.
O resultado é que, se alguém instalar o pacote de outra pessoa, o arquivo
package-lock.json
não estará envolvido. O conteúdo deste arquivo que o desenvolvedor do pacote possui não será levado em consideração ao instalar o pacote por outra pessoa.
Isso pode, por infeliz coincidência, levar ao problema de que falamos desde o início. No sistema do desenvolvedor, o código funciona bem e, em outros sistemas, produz erros. Mas o fato é que o desenvolvedor do projeto e aqueles que usam o projeto usam versões diferentes dos pacotes. Como consertar isso?
Recusa de arquivos de bloqueio e uso da tecnologia shrinkwrap
Primeiro, você precisa impedir a inclusão de arquivos de bloqueio no repositório do projeto. Ao usar o git, você precisa incluir o seguinte no arquivo
.gitignore
projeto:
yarn.lock package-lock.json
A documentação do yarn diz que o
yarn.lock
precisa ser adicionado ao repositório, mesmo que se trate de desenvolver a biblioteca que você planeja publicar. Mas se você quiser que você e os usuários da sua biblioteca trabalhem com o mesmo código, eu recomendaria incluir
yarn.lock
no arquivo
.gitignore
.
Você pode desativar a criação automática do arquivo
package-lock.json
.npmrc
arquivo
.npmrc
com o seguinte conteúdo à pasta do projeto:
package-lock=false
Ao trabalhar com yarn, você pode usar o
yarn install --no-lockfile
, que permite desativar a leitura do arquivo
yarn.lock
.
No entanto, o fato de termos nos livrado do arquivo
package-lock.json
não significa que não possamos capturar informações sobre dependências e dependências aninhadas. Há
outro arquivo chamado
npm-shrinkwrap.json
.
Em geral, esse
é o mesmo arquivo que o
package-lock.json
, é criado pelo
npm shrinkwrap
. Este arquivo entra no registro npm quando o pacote é publicado.
Para automatizar essa operação, o
npm shrinkwrap
pode ser incluído na seção de descrição do script do arquivo
package.json
como um script de
npm shrinkwrap
. Você pode obter o mesmo efeito usando o gancho de confirmação do git. Como resultado, você pode ter certeza de que, no seu ambiente de desenvolvimento, no seu sistema de CI, e os usuários do seu projeto usam as mesmas dependências.
Vale a pena notar que esta técnica é recomendada para ser usada com responsabilidade. Ao criar arquivos shrinkwrap, você confirma versões específicas das dependências. Por um lado, isso é útil para garantir a operação estável do projeto; por outro, pode impedir que os usuários instalem patches críticos, o que, caso contrário, seria feito automaticamente. De fato, o npm recomenda não usar arquivos shrinkwrap ao desenvolver bibliotecas, limitando seu uso a algo como sistemas de CI.
Localizando informações de pacote e dependência
Infelizmente, com toda a riqueza de informações sobre gerenciamento de dependências na
documentação do npm, às vezes é difícil navegar por essas informações. Se você quiser saber exatamente o que está instalado durante a instalação de dependências ou é empacotado antes de enviar o pacote para o npm, é possível, com comandos diferentes, usar o
--dry-run
. O uso desse sinalizador leva ao fato de que a equipe não afeta o sistema. Por exemplo, o
npm install --dry-run
não instala as dependências e o
npm publish --dry-run
não inicia o processo de publicação de pacotes.
Aqui estão alguns comandos semelhantes:
npm ci --dry-run # , package-lock.json npm-shrinkwrap.json npm pack --dry-run # , npm install <dep> --verbose --dry-run #
Sumário
Muito do que falamos aqui se baseia nas especificidades da execução de várias operações usando o npm. Estamos falando de empacotar, publicar, instalar pacotes, trabalhar com dependências. E, como o npm está em constante evolução, podemos dizer que tudo isso pode mudar no futuro. Além disso, a possibilidade de aplicação prática das recomendações fornecidas aqui depende de como o desenvolvedor do pacote percebe o problema de usar diferentes versões de dependências em diferentes ambientes.
Esperamos que este material tenha ajudado você a entender melhor como funciona o ecossistema de dependência npm. Se você quiser se aprofundar ainda mais nesta questão -
aqui você pode ler sobre as diferenças entre os
npm ci
e
npm install
.
Aqui você pode descobrir o que exatamente entra nos
npm-shrinkwrap.json
package-lock.json
e
npm-shrinkwrap.json
.
Aqui está a página de documentação do npm, onde você pode descobrir quais arquivos do projeto estão incluídos e não nos pacotes.
Caros leitores! Você usa o arquivo npm-shrinkwrap.json em seus projetos?
