Yarn: tornar `--pure-lockfile` padrão para` install`

Criado em 10 out. 2016  ·  54Comentários  ·  Fonte: yarnpkg/yarn

Você deseja solicitar um _feature_ ou denunciar um _bug_?

_recurso_

Qual é o comportamento atual?

Não passar --pure-lockfile para install comando me confunde porque ele modifica o arquivo de bloqueio ao instalar node_modules.
Nós concordamos na semântica de que add/upgrade/remove deve alterar dependências e install deve reconstruir consistentemente node_modules a partir de lockfile.

A consistência é perdida quando o arquivo de bloqueio é modificado, dependendo do ambiente (versão do yarn atualmente instalada).

Qual é o comportamento esperado?

Não escreva yarn.lock ou package.json ao fazer yarn install .
Para atualizar yarn.lock use yarn upgrade

Mencione seu node.js, yarn e versão do sistema operacional.

fio 0,14

cat-feature needs-discussion

Comentários muito úteis

Há um monte de coisas diferentes acontecendo aqui que eu queria tentar desvendar (sem trocadilhos).

Primeiro, as pessoas levantaram uma série de requisitos diferentes que considero incontroversos (e que tornam alguns dos comportamentos existentes bugs, dos quais falarei em breve).

Do relatório de bug original.

A consistência é perdida quando o arquivo de bloqueio é modificado, dependendo do ambiente (versão do yarn atualmente instalada).
Qual é o comportamento esperado?
Não escreva yarn.lock ou package.json ao fazer a instalação do yarn.
Para atualizar o yarn.lock, use a atualização do yarn

Para ser mais preciso, a semântica esperada, na minha opinião, é:

  • se package.json não mudou desde a última vez que yarn.lock mudou, yarn.lock é a fonte da verdade e não deve ser atualizado.
  • se package.json mudou desde a última vez, yarn.lock mudou, atualize yarn.lock para que satisfaça package.json e atualize node_modules .
  • se yarn update for executado, resolva novamente todas as dependências e obtenha a versão mais recente de tudo que satisfaça o package.json .

Isso significa que quando um repositório é clonado pela primeira vez em uma máquina , se o yarn.lock foi verificado, o yarn deve sempre tratá-lo como a fonte da verdade, não gerar atualizações para yarn.lock e pular diretamente para a etapa de busca.

Na medida em que esse não é o comportamento atual do fio, acredito que seria um bug.


@esphen escreveu:

Eu concordo. Deve haver uma discussão sobre por que yarn install grava um lockfile por padrão em primeiro lugar, já que parece estar em desacordo com todo o conceito de lockfile. Por que ter um arquivo de bloqueio se ele não está bloqueando as versões por padrão?

Acho que o que isso quer dizer é que o yarn não deve escrever um novo arquivo de bloqueio se o existente ainda estiver atualizado. Eu concordo com isso.

Concordo com a opinião de @bestander de que apenas ações mutantes devem atualizar o arquivo de bloqueio por padrão, ou seja, adicionar / atualizar / remover.

O principal problema aqui é se uma mudança em package.json deve fazer com que yarn.lock seja atualizado. Na minha opinião, se a mudança para package.json não for satisfeita pelo yarn.lock , ele deve atualizar o yarn.lock .

Uma invariante importante dos sistemas lockfile como o yarn é que, usando o fluxo de trabalho normal, os desenvolvedores podem ter certeza de que os pacotes que realmente são usados ​​quando executam seus aplicativos correspondem às versões especificadas em seus package.json . Se package.json ficar fora de sincronia com yarn.lock , isso não será verdade, e a única maneira de saber isso será para leitores humanos lerem cuidadosamente yarn.lock .

A melhor maneira para a maioria dos usuários pensar sobre o arquivo de bloqueio é que ele é um artefato do fio em execução que representa as versões precisas de todos os pacotes que foram usados ​​para os package.json atuais. Ao fazer o check-in, outros colaboradores, CI e código de produção têm a garantia de usar essas mesmas versões.


@Guuz disse:

Então, para verificar se entendi corretamente:
yarn instala todas as dependências e também modifica o lockfile. Em um servidor CI, você deve usar yarn install --pure-lockfile?

Esta pergunta ecoa um sentimento que algumas pessoas fizeram neste tópico.

A carga tem uma bandeira --locked que diz "se package.json não for satisfeito com yarn.lock , é um erro grave". Bundler tem um sinalizador semelhante ( --frozen ), que foi adicionado quando o Heroku adotou o Bundler, para dar às pessoas um erro grave caso fizessem alterações locais em seus Gemfile e se esquecessem de fazer o check-in de Gemfile.lock .

A ideia é que durante o seu desenvolvimento normal, você gostaria de ser capaz de fazer alterações em package.json e fazer com que o yarn.lock ficasse em sincronia (novamente, para garantir que as versões especificadas em package.json sempre coincidir com o que é usado na prática).

Mas, durante a implantação, é quase sempre um erro ter divergido, porque significa que você fez uma alteração em package.json , executou um comando yarn e se esqueceu de fazer o check-in yarn.lock . Isso significa que as versões em seu package.json não correspondem às versões reais usadas quando o aplicativo é executado , o que dizemos que viola uma invariante fundamental do yarn.


@esphen disse:

Na minha opinião, uma das funções que um gerenciador de pacotes desempenha é facilitar ao máximo o início do desenvolvimento de um projeto. Uma simples instalação do yarn deve obter todos os pacotes de que você precisa para começar a desenvolver, sem nenhuma confusão envolvida.

Acho isso incontroverso.

Com o npm, tive muitas instâncias de desenvolvedores que ingressaram em um projeto, apenas para descobrir que um projeto não funciona em sua máquina. Essas instâncias ocorreram devido a dependências temporárias que impulsionaram as versões para versões com alterações significativas ou simplesmente não seguindo o semver. Eu esperava que o yarn resolvesse esses problemas, mas se a conclusão é que todos os desenvolvedores em um projeto devem executar yarn install --pure-lockfile para ter 100% de certeza de que o projeto será construído, então esse não é o caso.

Executar yarn install --pure-lockfile significará que o arquivo de bloqueio será respeitado mesmo se as versões dentro do arquivo de bloqueio entrarem em conflito com as versões especificadas em package.json . Isso só deve ocorrer se um desenvolvedor esquecer de fazer o check-in de seu yarn.lock após fazer alterações em package.json .

Outra função de um gerenciador de pacotes é fornecer aos projetos o controle de suas dependências. Se for feito puro por padrão, os desenvolvedores podem dar uma olhada no fio desatualizado para ver as versões desatualizadas e, em seguida, revisar as notas de alteração, evitando quaisquer alterações interrompidas. Isso daria aos desenvolvedores controle total para apenas alterar as versões em um determinado período de lançamento, em vez de proibir os desenvolvedores de fazer git commit -a para evitar commits de arquivo de bloqueio acidentais.

Se package.json não mudou, na minha opinião é um bug se yarn.lock está sendo atualizado. Pelo menos um caso de bug parece estar no relatório original:

lockfile é modificado dependendo do ambiente (versão do yarn atualmente instalada).

Acho que isso é um erro e deve ser corrigido.

Mais tarde no tópico, @thejameskyle disse:

Imagine uma função memoize em que a entrada é um package.json e a saída é yarn.lock.

Esse é exatamente o modelo mental correto, na minha opinião (" yarn.lock pode mudar se e somente se package.json mudar"), e se a abstração vazar, devemos consertar.


@adamchainz disse:

Mais informações sobre o acima: nosso build tem coffeescript do Github como uma subdependência. coffeescript empurrou alguns commits e obtivemos um yarn.lock modificado em nosso processo de compilação executando apenas yarn install

e depois:

Mas tem o mau comportamento se uma dependência está sendo instalada a partir do github, como eu relatei acima

O problema aqui é que o yarn não trata o git sha como parte da versão bloqueada das dependências do git. Cargo e Bundler têm o conceito de uma versão "precisa" que é serializada no arquivo de bloqueio; para fontes git, a versão "precisa" é o SHA. Então, quando você faz um novo clone com apenas package.json e yarn.lock e executa yarn , todas as informações necessárias para obter precisamente o código de que você precisa estão lá.

Devo confessar que perdi essa interação ao revisar o código git original; há algum rastreamento SHA no código, mas yarn install não garante que o gráfico de dependência hidratada o respeite.


TL; DR

Concordo com @thejameskyle e @kittens que yarn.lock deve ser mantido em sincronia com package.json automaticamente, porque acredito que os usuários devem ser capazes de assumir que as versões especificadas em seus package.json alinhar com o que é usado quando seu aplicativo é executado.

No entanto, parece haver alguns bugs que estão causando rotatividade inadequada no yarn.lock mesmo quando o package.json não mudou:

  • mudanças na versão do yarn nas máquinas atualizam o arquivo de bloqueio
  • as dependências do git são atualizadas mesmo que package.json não tenha sido atualizado, o que então atualiza o arquivo de bloqueio

Devemos também considerar algo como a bandeira --locked da Cargo, que você pode usar em CI para falhar rapidamente a compilação se um desenvolvedor atualizar o package.json e esquecer de verificar o yarn.lock atualizado

Todos 54 comentários

Eu concordo. Deve haver uma discussão sobre por que yarn install grava um arquivo de bloqueio por padrão em primeiro lugar, já que parece estar em desacordo com o conceito inteiro de arquivo de bloqueio. Por que ter um arquivo de bloqueio se ele não está bloqueando as versões por padrão?

Existe um caso para yarn install criar um arquivo de bloqueio se nenhum estiver presente, ou seja, quando alguém está convertendo um projeto para usar yarn , mas a razão para sempre escrevê-lo não é clara. Eu concordo com a opinião de @bestander de que apenas ações mutantes devem atualizar o arquivo de bloqueio por padrão, ou seja, add/upgrade/remove .

Deve haver uma maneira de modificar o arquivo de bloqueio sem add/remove/upgrade ex: no cenário quando você atualiza o Yarn e ele usa uma nova versão do arquivo de bloqueio?

Suponho que a opção poderia ser invertida

yarn install --save-lockfile

Em 17 de outubro de 2016 às 18:53, James Ide [email protected] escreveu:

Deve haver uma maneira de modificar o arquivo de bloqueio sem adicionar / remover / atualizar
ex: no cenário quando você atualiza o Yarn e usa um novo arquivo de bloqueio
versão?

-
Você está recebendo isso porque foi mencionado.
Responda a este e-mail diretamente, visualize-o no GitHub
https://github.com/yarnpkg/yarn/issues/570#issuecomment -254282256 ou mudo
o segmento
https://github.com/notifications/unsubscribe-auth/ACBdWJLpdvqiwcBwqE4KB3x3f4oCn_nVks5q07YYgaJpZM4KSlSw
.

Eu também estou confuso com isso. Qual é o motivo do comportamento padrão atual?

Afaik, não havia razões fortes para o comportamento padrão.
A ideia, suponho, é manter os arquivos de bloqueio das pessoas "perenes".

BTW PR é bem-vindo

Acho que a razão para isso foi que o fio foi originalmente projetado com um único comando install que foi dividido em install/add/upgrade

Então, para verificar se entendi corretamente:

yarn instala todas as dependências e também modifica o arquivo de bloqueio. Em um servidor de CI, você deve usar yarn install --pure-lockfile ?
Por que o lockfile é modificado durante uma instalação? Já que você não está atualizando nada ... Yarn deve apenas instalar os pacotes conforme descrito no lockfile, certo?

Obrigada pelo esclarecimento!

O problema é que se o arquivo de bloqueio for puro por padrão, as pessoas vão se esquecer de atualizá-lo, pois seria um comando separado.

@kittens O arquivo de bloqueio não deve ser atualizado apenas ao adicionar / remover / atualizar qualquer pacote? Esses devem sempre atualizar o arquivo de bloqueio, bem como uma instalação inicial.

O problema é que se o arquivo de bloqueio for puro por padrão, as pessoas vão se esquecer de atualizá-lo, pois seria um comando separado

Ser um problema depende do que você considera ser o objetivo principal de um gerenciador de pacotes.

Na minha opinião, uma das funções que um gerenciador de pacotes desempenha é facilitar ao máximo o início do desenvolvimento de um projeto. Um simples yarn install deve receber todos os pacotes que você precisa para começar a desenvolver, sem nenhuma confusão envolvida.

Com npm , tive muitas instâncias de desenvolvedores ingressando em um projeto, apenas para descobrir que um projeto não funciona em sua máquina. Essas instâncias ocorreram devido a dependências temporárias que impulsionaram as versões para versões com alterações significativas ou simplesmente não seguindo o semver. Eu esperava que yarn resolvesse esses problemas, mas se a conclusão é que todos os desenvolvedores em um projeto devem executar yarn install --pure-lockfile para ter 100% de certeza de que o projeto vai ser construído, então isso não é O caso.

Outra função de um gerenciador de pacotes é fornecer aos projetos o controle de suas dependências. Se for feito puro por padrão, os desenvolvedores podem dar uma olhada em yarn outdated para ver as versões desatualizadas e, em seguida, revisar as notas de alteração, evitando alterações interruptivas. Isso daria aos desenvolvedores controle total para apenas alterar as versões em um determinado período de lançamento, em vez de proibir os desenvolvedores de fazer git commit -a para evitar commits de arquivos de bloqueio acidentais.

Eu concordo com tudo o que @esphen diz. Estou surpreso de que o comportamento puro não seja o padrão no Yarn - pensei que esse tipo de consistência fosse o principal benefício que o Yarn tinha sobre o NPM. Esse deve ser o motivo mais convincente para mudar do NPM da forma como eu o vejo.

Nos surpreendeu totalmente quebrando a compilação depois que começamos a usar yarn por alguns dias. Sinceramente, pensei que --pure-lockfile era o comportamento padrão depois de ler grande parte da documentação e sobre como ele é melhor do que o npm com embalagem plástica. Por favor, torne o padrão :)

@ide Imagine um cenário em que alguém está apenas usando npm e atualiza package.json , como yarn.lock será atualizado?

Alguém pode escrever os cenários que levam ao lockfile sendo modificado inesperadamente? Esta mudança é grave e faz o lockfile um cidadão de segunda classe, exigindo atualizações para que ele seja explícito o que significa um monte de sobrecarga em lembrar que operações resultar em que está sendo atualizado etc.

Mais informações sobre o acima: nosso build tem coffeescript do Github como uma subdependência. coffeescript empurrou alguns commits e obtivemos um yarn.lock modificado em nosso processo de compilação executando apenas yarn install :

diff --git a/foo/yarn.lock b/foo/yarn.lock
index ec667fa..bb1f6ae 100644
--- a/foo/yarn.lock
+++ b/foo/yarn.lock
@@ -930,9 +930,9 @@ code-point-at@^1.0.0:
   version "1.6.3"
   resolved "https://registry.yarnpkg.com/coffee-script/-/coffee-script-1.6.3.tgz#6355d32cf1b04cdff6b484e5e711782b2f0c39be"

-"coffee-script<strong i="8">@github</strong>:jashkenas/coffeescript":
+coffee-script@jashkenas/coffeescript:
   version "1.11.1"
-  resolved "https://codeload.github.com/jashkenas/coffeescript/tar.gz/887052de079b2f0af9f080031a00bb7544eaca08"
+  resolved "https://codeload.github.com/jashkenas/coffeescript/tar.gz/0d132318ce8f7116a436d97db1f2a5c8b1dedf28"

 [email protected]:
   version "0.3.0"

Alguém pode escrever os cenários que levam ao lockfile sendo modificado inesperadamente? Esta mudança é séria e torna o arquivo de bloqueio um cidadão de segunda classe, exigindo que as atualizações sejam explícitas, o que significa uma grande sobrecarga ao lembrar quais operações resultam em sua atualização etc.

Percebo yarn install como um comando que cria node_modules para mim.
É o oposto de yarn add e yarn remove que modificam package.json, yarn.lock e cleanup node_modules.
Ao contrário de add e remove , corro install 100 vezes mais frequentemente, especialmente em CI, onde nunca espero ter efeitos colaterais.

Exemplos de quando não espero que as coisas mudem:

  1. Estou no Yarn 0.15.0, meus companheiros de equipe estão no Yarn 0.16.0.
    Como o 0.16.0 adicionou espaços entre as entradas em yarn.lock toda vez que executo yarn install em yarn.lock gerado por meus companheiros de equipe, recebo um arquivo yarn.lock modificado que preciso lembrar de não enviar.
    E vice versa.
  2. Minhas outras ferramentas de construção dependem de yarn.lock como "a fonte da verdade" do estado node_modules. Se mudar inesperadamente, terei não determinismo em minhas compilações

@kittens

O problema é que se o arquivo de bloqueio for puro por padrão, as pessoas vão se esquecer de atualizá-lo, pois seria um comando separado.

Imagine um cenário em que alguém está apenas usando o npm e atualiza o package.json, como o yarn.lock será atualizado?

Se assumirmos que yarn install não deve atualizar yarn.lock , então também deve falhar se yarn.lock estiver fora de sincronia com package.json para destacar o fato de que yarn install --save-lockfile é necessário para trazer tudo de volta em sincronia.

A instalação do fio +1 não deve alterar o yarn.lock

  1. O depurador é um aplicativo oss. Queremos que os contribuidores possam instalar o yarn e obter as _boas_ versões. Tivemos pessoas que instalaram o npm e disseram que está quebrando por causa de propriedades transitivas. Com a instalação do fio, os contribuidores instalam o fio e não sabem o que fazer com as mudanças de bloqueio do fio.

Não estou preocupado em atualizar o arquivo de bloqueio. Idealmente, o greenkeeper faria isso quando as dependências mudassem e pudéssemos mesclar a mudança do arquivo de bloqueio então.

Quero atualizar este problema com os pensamentos atuais sobre ele. @kittens e eu achamos que --pure-lockfile _não_ deveria ser o padrão por alguns motivos.

Começa com como as pessoas adicionam / removem / atualizam dependências. Embora existam comandos para ele, é prática comum atualizar manualmente o package.json manualmente ou por outra ferramenta como o Lerna .

Depois de modificar manualmente o package.json a expectativa tanto no Yarn quanto no npm é que, ao executar outra instalação, ele _sincronize_ com package.json . Nesse sentido, yarn install quase poderia ser renomeado para yarn sync .

No tópico de sincronização, ao executar uma instalação com novas dependências, você espera que o diretório node_modules reflita essas alterações. Como yarn.lock atua como um assistente de node_modules você deve esperar que ele permaneça em sincronia da mesma maneira.

Seu package.json é a fonte suprema da verdade, essa é sua interface para o yarn, é sua configuração e é a única coisa com a qual você deve se preocupar. Em um mundo ideal, você simplesmente compromete seus yarn.lock e nunca mais terá que pensar sobre isso novamente.


Por outro lado, acredito que muitas pessoas que estão expressando seu apoio a este problema estão confusas sobre o que realmente está sendo discutido aqui.

Usar --pure-lockfile por padrão não significa que o Yarn não produz resultados consistentes e confiáveis. O mesmo package.json resultará nos mesmos yarn.lock que resultará nos mesmos node_modules 100% das vezes.

Quando você atualiza suas package.json suas yarn.lock atualizações de arquivo e, em seguida, suas node_modules atualizações. Essa é uma ordem muito natural para as coisas e devemos mantê-la assim


Em relação ao CI ser capaz de obter dependências diferentes quando você atualizou seu package.json mas não executou yarn install para sincronizar tudo o que tenho certeza que alguém abrirá (embora eu não veja como um problema) - eu e outros temos conversado com várias ferramentas de CI sobre a integração do Yarn, podemos facilmente fazer com que eles usem --pure-lockfile por padrão, se as pessoas virem isso como um grande problema.


Se tivéssemos que fazer essa alteração, ela teria um impacto negativo com muito mais frequência ao alterar as dependências. Pelas razões que listei, acho que devemos encerrar este problema.

@thejameskyle Eu agradeceria se você pudesse esclarecer algo:

  1. Um desenvolvedor tem um package.json que contém uma dependência "foo": "^1.0.0"
  2. O desenvolvedor executa yarn install . O pacote foo está atualmente na versão 1.0.0 , então ele cria um arquivo yarn.lock que bloqueia em [email protected]
  3. O desenvolvedor adiciona yarn.lock ao Git.
  4. O desenvolvedor executa testes de unidade em sua cópia local do repo, tudo funciona bem.
  5. O desenvolvedor envia seu repo para CI (por exemplo, Travis).
  6. CI executa yarn install , mas foo agora foi atualizado para a versão 1.1.0 , então Yarn instala [email protected] e sobrescreve yarn.lock com a nova versão de foo
  7. O IC falha porque foo teve uma alteração significativa na versão 1.1.0

Aqui está uma situação semelhante:

  1. Um desenvolvedor tem um package.json que contém uma dependência "foo": "^1.0.0" , que está bloqueado como [email protected] , e yarn.lock é salvo no Git.
  2. Os testes de unidade funcionam bem na cópia local do desenvolvedor do repositório.
  3. Um contribuidor clona o repo com a intenção de fazer uma modificação + solicitação de pull.
  4. Quando o contribuidor executa yarn install ele obtém a versão [email protected] que faz com que yarn.lock seja atualizado.
  5. Agora a compilação do contribuidor está corrompida porque foo teve uma alteração significativa na versão 1.1.0

Acho que esse é o tipo de situação com que a maioria das pessoas se preocupa.

Portanto, se você pudesse esclarecer que o comportamento atual de yarn install não tem os problemas acima, acho que isso eliminaria muitos de nossos medos. : +1:

Nenhuma dessas situações se aplica. Só porque uma dependência foi atualizada, não significa que você a receberá, apenas se tiver feito alterações em package.json .

Vou apenas encerrar este assunto porque realmente parece que essa é a única preocupação que as pessoas têm, o que, como eu disse, não é um cenário real. Esse problema provavelmente está causando mais confusão.

Mas tem o mau comportamento se uma dependência está sendo instalada a partir do github, como eu relatei acima

@adamchainz Isso deve ser corrigido separadamente, podemos facilmente bloqueá-lo no commit

Nenhuma dessas situações se aplica. Só porque uma dependência foi atualizada, não significa que você a receberá, apenas se tiver feito alterações em package.json .

@thejameskyle : Não tenho certeza se entendi por que esse não é um cenário real. Você poderia, por favor, explicar?

Imagine uma função memoize onde a entrada é package.json e a saída é yarn.lock .

  1. A primeira vez que você passa um package.json ele cria um yarn.lock e armazena o resultado em cache.
  2. Da próxima vez que você executar _teste mesmo_ package.json o resultado será exatamente o mesmo porque está armazenado em cache.
  3. Ao alterar o package.json você invalidou o cache e agora o yarn.lock será recalculado.

O que estamos falando agora é nos livrarmos de # 3 e, em vez disso, tratar yarn.lock como se não tivesse sido invalidado pelo package.json alterado. O que seria muito estranho para uma função memoize ter e seria um comportamento muito estranho para Yarn ter.

O que acontece com um pacote em termos de commits e novas versões _deve_ ser irrelevante (se tivermos um bug com git commits, devemos consertar isso separadamente, mas não está relacionado a esse problema).

É mais complexo do que eu imaginei (cada versão de pacote é efetivamente "memoizada" individualmente, mudar a versão de um pacote não invalida o resto), mas espero que agora todos entendam.

@thejameskyle : Por uma questão de clareza (e curiosidade), digamos que eu tenho um projeto com um arquivo yarn.lock e alguém puxa o repositório. Sem executar yarn install ou npm install , essa pessoa adiciona uma nova dependência ao arquivo package.json e executa yarn install . O arquivo yarn.lock será completamente desconsiderado neste caso?

Há um monte de coisas diferentes acontecendo aqui que eu queria tentar desvendar (sem trocadilhos).

Primeiro, as pessoas levantaram uma série de requisitos diferentes que considero incontroversos (e que tornam alguns dos comportamentos existentes bugs, dos quais falarei em breve).

Do relatório de bug original.

A consistência é perdida quando o arquivo de bloqueio é modificado, dependendo do ambiente (versão do yarn atualmente instalada).
Qual é o comportamento esperado?
Não escreva yarn.lock ou package.json ao fazer a instalação do yarn.
Para atualizar o yarn.lock, use a atualização do yarn

Para ser mais preciso, a semântica esperada, na minha opinião, é:

  • se package.json não mudou desde a última vez que yarn.lock mudou, yarn.lock é a fonte da verdade e não deve ser atualizado.
  • se package.json mudou desde a última vez, yarn.lock mudou, atualize yarn.lock para que satisfaça package.json e atualize node_modules .
  • se yarn update for executado, resolva novamente todas as dependências e obtenha a versão mais recente de tudo que satisfaça o package.json .

Isso significa que quando um repositório é clonado pela primeira vez em uma máquina , se o yarn.lock foi verificado, o yarn deve sempre tratá-lo como a fonte da verdade, não gerar atualizações para yarn.lock e pular diretamente para a etapa de busca.

Na medida em que esse não é o comportamento atual do fio, acredito que seria um bug.


@esphen escreveu:

Eu concordo. Deve haver uma discussão sobre por que yarn install grava um lockfile por padrão em primeiro lugar, já que parece estar em desacordo com todo o conceito de lockfile. Por que ter um arquivo de bloqueio se ele não está bloqueando as versões por padrão?

Acho que o que isso quer dizer é que o yarn não deve escrever um novo arquivo de bloqueio se o existente ainda estiver atualizado. Eu concordo com isso.

Concordo com a opinião de @bestander de que apenas ações mutantes devem atualizar o arquivo de bloqueio por padrão, ou seja, adicionar / atualizar / remover.

O principal problema aqui é se uma mudança em package.json deve fazer com que yarn.lock seja atualizado. Na minha opinião, se a mudança para package.json não for satisfeita pelo yarn.lock , ele deve atualizar o yarn.lock .

Uma invariante importante dos sistemas lockfile como o yarn é que, usando o fluxo de trabalho normal, os desenvolvedores podem ter certeza de que os pacotes que realmente são usados ​​quando executam seus aplicativos correspondem às versões especificadas em seus package.json . Se package.json ficar fora de sincronia com yarn.lock , isso não será verdade, e a única maneira de saber isso será para leitores humanos lerem cuidadosamente yarn.lock .

A melhor maneira para a maioria dos usuários pensar sobre o arquivo de bloqueio é que ele é um artefato do fio em execução que representa as versões precisas de todos os pacotes que foram usados ​​para os package.json atuais. Ao fazer o check-in, outros colaboradores, CI e código de produção têm a garantia de usar essas mesmas versões.


@Guuz disse:

Então, para verificar se entendi corretamente:
yarn instala todas as dependências e também modifica o lockfile. Em um servidor CI, você deve usar yarn install --pure-lockfile?

Esta pergunta ecoa um sentimento que algumas pessoas fizeram neste tópico.

A carga tem uma bandeira --locked que diz "se package.json não for satisfeito com yarn.lock , é um erro grave". Bundler tem um sinalizador semelhante ( --frozen ), que foi adicionado quando o Heroku adotou o Bundler, para dar às pessoas um erro grave caso fizessem alterações locais em seus Gemfile e se esquecessem de fazer o check-in de Gemfile.lock .

A ideia é que durante o seu desenvolvimento normal, você gostaria de ser capaz de fazer alterações em package.json e fazer com que o yarn.lock ficasse em sincronia (novamente, para garantir que as versões especificadas em package.json sempre coincidir com o que é usado na prática).

Mas, durante a implantação, é quase sempre um erro ter divergido, porque significa que você fez uma alteração em package.json , executou um comando yarn e se esqueceu de fazer o check-in yarn.lock . Isso significa que as versões em seu package.json não correspondem às versões reais usadas quando o aplicativo é executado , o que dizemos que viola uma invariante fundamental do yarn.


@esphen disse:

Na minha opinião, uma das funções que um gerenciador de pacotes desempenha é facilitar ao máximo o início do desenvolvimento de um projeto. Uma simples instalação do yarn deve obter todos os pacotes de que você precisa para começar a desenvolver, sem nenhuma confusão envolvida.

Acho isso incontroverso.

Com o npm, tive muitas instâncias de desenvolvedores que ingressaram em um projeto, apenas para descobrir que um projeto não funciona em sua máquina. Essas instâncias ocorreram devido a dependências temporárias que impulsionaram as versões para versões com alterações significativas ou simplesmente não seguindo o semver. Eu esperava que o yarn resolvesse esses problemas, mas se a conclusão é que todos os desenvolvedores em um projeto devem executar yarn install --pure-lockfile para ter 100% de certeza de que o projeto será construído, então esse não é o caso.

Executar yarn install --pure-lockfile significará que o arquivo de bloqueio será respeitado mesmo se as versões dentro do arquivo de bloqueio entrarem em conflito com as versões especificadas em package.json . Isso só deve ocorrer se um desenvolvedor esquecer de fazer o check-in de seu yarn.lock após fazer alterações em package.json .

Outra função de um gerenciador de pacotes é fornecer aos projetos o controle de suas dependências. Se for feito puro por padrão, os desenvolvedores podem dar uma olhada no fio desatualizado para ver as versões desatualizadas e, em seguida, revisar as notas de alteração, evitando quaisquer alterações interrompidas. Isso daria aos desenvolvedores controle total para apenas alterar as versões em um determinado período de lançamento, em vez de proibir os desenvolvedores de fazer git commit -a para evitar commits de arquivo de bloqueio acidentais.

Se package.json não mudou, na minha opinião é um bug se yarn.lock está sendo atualizado. Pelo menos um caso de bug parece estar no relatório original:

lockfile é modificado dependendo do ambiente (versão do yarn atualmente instalada).

Acho que isso é um erro e deve ser corrigido.

Mais tarde no tópico, @thejameskyle disse:

Imagine uma função memoize em que a entrada é um package.json e a saída é yarn.lock.

Esse é exatamente o modelo mental correto, na minha opinião (" yarn.lock pode mudar se e somente se package.json mudar"), e se a abstração vazar, devemos consertar.


@adamchainz disse:

Mais informações sobre o acima: nosso build tem coffeescript do Github como uma subdependência. coffeescript empurrou alguns commits e obtivemos um yarn.lock modificado em nosso processo de compilação executando apenas yarn install

e depois:

Mas tem o mau comportamento se uma dependência está sendo instalada a partir do github, como eu relatei acima

O problema aqui é que o yarn não trata o git sha como parte da versão bloqueada das dependências do git. Cargo e Bundler têm o conceito de uma versão "precisa" que é serializada no arquivo de bloqueio; para fontes git, a versão "precisa" é o SHA. Então, quando você faz um novo clone com apenas package.json e yarn.lock e executa yarn , todas as informações necessárias para obter precisamente o código de que você precisa estão lá.

Devo confessar que perdi essa interação ao revisar o código git original; há algum rastreamento SHA no código, mas yarn install não garante que o gráfico de dependência hidratada o respeite.


TL; DR

Concordo com @thejameskyle e @kittens que yarn.lock deve ser mantido em sincronia com package.json automaticamente, porque acredito que os usuários devem ser capazes de assumir que as versões especificadas em seus package.json alinhar com o que é usado quando seu aplicativo é executado.

No entanto, parece haver alguns bugs que estão causando rotatividade inadequada no yarn.lock mesmo quando o package.json não mudou:

  • mudanças na versão do yarn nas máquinas atualizam o arquivo de bloqueio
  • as dependências do git são atualizadas mesmo que package.json não tenha sido atualizado, o que então atualiza o arquivo de bloqueio

Devemos também considerar algo como a bandeira --locked da Cargo, que você pode usar em CI para falhar rapidamente a compilação se um desenvolvedor atualizar o package.json e esquecer de verificar o yarn.lock atualizado

@thejameskyle Obrigado! : heart: Eu concordo com você e @kittens que yarn.lock deve ser atualizado após alterar package.json

@wycats Uma --locked (ou semelhante). Devemos criar uma nova questão sobre isso.

Feito # 1568 para rastrear o problema do git SHA

@wycats , obrigado pela visão geral reveladora e muito perspicaz!

Isso significa que quando um repositório é clonado pela primeira vez em uma máquina, se o yarn.lock foi verificado, o yarn deve sempre tratá-lo como a fonte da verdade, não gerar atualizações para o yarn.lock e pular diretamente para a etapa de busca.
Na medida em que esse não é o comportamento atual do fio, acredito que seria um bug.

Este é exatamente o cenário pelo qual esta edição foi aberta.
Temos algumas versões ativas do Yarn na empresa e, em nossa escala, não acho que seremos capazes de fazer atualizações atômicas em todos os lugares.
As compilações no yarn 0.13, 0.14 e 0.15 introduziram pequenas variações nos arquivos yarn.lock, embora o package.json estivesse em sincronia.
Isso causou alguns problemas, por exemplo, as compilações de Buck foram retardadas porque as mudanças na árvore de origem invalidam os caches.
Isso fez com que eu e algumas equipes trabalhassem algumas horas.

@thejameskyle , obrigado por compartilhar sua opinião.
Não considerei justo o cenário de package.json fora de sincronia com yarn.lock. E você tem um ponto válido.

No entanto, como @wycats apontou, o relatório de bug original é válido.
Corrigir isso é importante para ter compilações válidas e reabrirei o problema com a intenção de apresentar uma solução que satisfaça todas as partes interessadas.

@wycats

Para ser mais preciso, a semântica esperada, na minha opinião, é:

  • se package.json não mudou desde a última vez que yarn.lock mudou, yarn.lock é a fonte da verdade e não deve ser atualizado.
  • se package.json mudou desde a última vez, yarn.lock mudou, atualize yarn.lock para que satisfaça package.json e atualize node_modules .
  • se yarn update for executado, resolva novamente todas as dependências e obtenha a versão mais recente de tudo que satisfaça o package.json .

Isso significa que quando um repositório é clonado pela primeira vez em uma máquina , se o yarn.lock foi verificado, o yarn deve sempre tratá-lo como a fonte da verdade, não gerar atualizações para yarn.lock e pular diretamente para a etapa de busca.

Estas são as semânticas que seguimos e adicionei em # 364.

@bestander Você esteve envolvido no PR (# 364) que implementou essas heurísticas. Que mudanças adicionais você está propondo?

Este problema é extremamente amplo e já concordamos que --pure-lockfile não será o padrão e seguiremos as heurísticas descritas por @wycats. Se esse problema for mantido em aberto, o título precisa refletir o problema atual com esse comportamento.

@kittens parece bom, atualizarei o problema.
Ou talvez eu deva abrir um novo relacionado à instalação, alterando o arquivo de bloqueio quando o package.json não mudou

Podemos passar para um novo problema? Esses comentários aqui podem apenas ser preservados como um arquivo

Parece bom, @thejameskyle , vou criar um novo problema hoje e criar um link aqui

Criado o novo problema em foco https://github.com/yarnpkg/yarn/issues/1576

seria interessante ter a opção de fazer yarn install falhar se o pacote em package.json não estiver em yarn.lock, ou seja. falha se algum pacote não estiver bloqueado

Adicionando esclarecimentos que ainda eram ambíguos para mim depois de ler o acima:

tldr; Mudanças não relacionadas em package.json não irão atualizar um pacote para a versão mais recente compatível com seu package.json semver inalterado.

Com base em algumas das palavras acima, parecia que yarn.lock foi armazenado em cache com chave em um hash package.json e, portanto, parecia que yarn.lock seria gravado em (atualizado / cache invalidado ) em qualquer alteração em package.json , o que seria problemático, pois uma alteração não relacionada (ou seja, atualizar para "description" ou outra dependência) pode fazer com que a versão yarn.lock dessa dependência seja atualizada para uma versão mais recente dentro do mesmo package.json existente.

No entanto, verifiquei que a entrada yarn.lock um pacote só é gravada quando o package.json semver correspondente é atualizado (mesmo se o novo semver for compatível com a versão yarn.lock , e consequentemente, não precisaria de uma atualização de versão).

Por exemplo,

  • Digamos que yarn add lodash@^4.17.1 instala [email protected]
  • Posteriormente, [email protected] estará disponível.
  • o yarn continuará a instalar [email protected]
  • A menos que / até que a versão do lodash seja alterada em package.json (ou adicionar / atualizar / remover yarn é executado especificamente no lodash).

Breadcrumb # 1576

A propósito, se você estiver disposto a contribuir com os documentos com pequenos artigos como este, que seriam ótimos para a comunidade.
A equipe principal está ocupada corrigindo problemas e adicionando novos recursos, o que é esperado e apreciado se a comunidade ajudar a manter a documentação

@CrabDude obrigado por compartilhar seus esclarecimentos.

Você quer dizer - em seu exemplo acima - que apenas lodash e suas próprias dependências terão suas versões de bloqueio atualizadas em yarn.lock ? por exemplo, mesmo se outra dependência puder ter uma nova versão de bloqueio, ela não será atualizada ao mesmo tempo?

Ou um segundo exemplo: Digamos que yarn.lock esteja severamente desatualizado e o usuário execute yarn add para adicionar uma nova dependência ao package.json. Todos os outros pacotes desatualizados serão atualizados em yarn.lock ou permanecerão os mesmos?

@rarkins

Você quer dizer - em seu exemplo acima - que apenas lodash e suas próprias dependências terão suas versões de bloqueio atualizadas em yarn.lock?

sim. Isso parece ser confirmado em meu exemplo.

Todos os outros pacotes desatualizados serão atualizados em yarn.lock ou permanecerão os mesmos?

Parece que as não lodash árvores de dependência / entradas de bloqueio de pacotes não seriam atualizadas; apenas as subdependências de lodash seriam.

Do meu ponto de vista, cada um deles é desejável e esperado.

Prefácio : Eu amo fios. Mas isso me frustra infinitamente.

Na minha empresa, yarn install muda o arquivo de bloqueio constantemente em máquinas diferentes (cada uma executando a mesma versão), apesar de nunca mudar package.json . E quando o fazemos, atualizamos usando yarn add . Isso é irritante porque o CI verifica se o status do git está limpo após uma compilação para ter certeza de que não esquecemos de fazer coisas como verificar um arquivo de bloqueio, e ele muda frequentemente.

Minha expectativa do yarn era que ele garantiria node_modules idênticos em todas as máquinas _por padrão_. Não com sinalizadores extras. Isso priorizaria a correção sobre a conveniência. Se eu quisesse incerteza, poderia usar o npm diretamente. Quando um arquivo é alterado, é um sinal de que algo o mudou e devo examiná-lo. Não deve mudar.

Perguntas

  • Está sendo dito que, apesar do lockfile ser alterado, o conteúdo de node_modules será sempre idêntico ao de quando foi gerado? Não acredito que seja esse o caso, mas se for, então eu entendo a confusão neste tópico - isso significaria que o fio faz a coisa certa, apesar de parecer que não.
  • Quando package.json muda, o lockfile é regenerado. Isso não poderia alterar acidentalmente muitas dependências, dependendo do estado dos node_modules desse programador em particular? O fio deve determinar um delta e tentar preservar os bloqueios existentes da melhor maneira possível (se ainda não o fizer).
  • Por que yarn add especifica versões em package.json com ^ ? Mais uma vez, entendi que a promessa do yarn era congelar as dependências.

Bugs Relacionados

  • Quando um pacote aleatório é excluído em node_modules , yarn install indica sucesso sem reinstalá-lo. Quando muitos deles acabam, ele os reinstala. npm é um pouco mais completo a esse respeito.
  • O lockfile tende a ser regenerado se você deletar node_modules e fazer uma instalação limpa (que é literalmente o oposto do que você esperaria - eu espero que ele instale exatamente o que está no lockfile e não faça absolutamente nada mais)
  • Se você deletar o arquivo de bloqueio sem tocar no pacote ou node_modules após uma instalação limpa, o yarn o regenera e é geralmente muito diferente da versão anterior. É como um compilador que produz um código diferente a cada vez que você o executa, apesar de não mudar nada.

No geral, o yarn torna as instalações mais rápidas, mas parece falhar em sua (in) competência principal: Congelar versões, de forma consistente, por padrão. Não preciso de conveniências que me ajudem a iniciar meu projeto, preciso de ajuda para mantê-lo em uma equipe enorme por muitos anos. Os programadores são inteligentes e intencionais, quando querem uma mudança, eles pedem explicitamente.

O arquivo de bloqueio em constante mudança não inspira confiança e é um incômodo constante. Eu prefiro avisos e erros de que package.json não corresponde ao lockfile, que o lockfile não corresponde a node_modules, que uma versão bloqueada não existe mais, etc., para que minhas compilações parem imediatamente e eu posso tomar decisões intencionais sobre minhas dependências.

@jspiro , obrigado por escrever isso.
Existem algumas questões levantadas aqui.
Seria melhor abrir cada problema separadamente, caso contrário, eles se perderão nos comentários.

Você está usando a versão mais recente do Yarn?
A partir de 0,18-0,19, não vemos modificações nos arquivos yarn.lock entre as máquinas.

Perguntas:

Está sendo dito que, apesar do lockfile ser alterado, o conteúdo de node_modules será sempre idêntico ao de quando foi gerado? Não acredito que seja esse o caso, mas se for, então eu entendo a confusão neste tópico - isso significaria que o fio faz a coisa certa, apesar de parecer que não.

Dev e dependências opcionais podem ser deixadas de fora para o mesmo arquivo de bloqueio.
Mas aqueles que estão bing instalados, exceto para pacotes específicos da plataforma, node_modules deve ter pacotes idênticos em locais idênticos.

Quando o package.json muda, o lockfile é regenerado. Isso não poderia alterar acidentalmente muitas dependências, dependendo do estado dos node_modules desse programador em particular? O fio deve determinar um delta e tentar preservar os bloqueios existentes da melhor maneira possível (se ainda não o fizer).

Esse é um bom pedido de recurso, adoraria ver um PR para isso.

Por que yarn add especifica versões em package.json com um ^? Mais uma vez, entendi que a promessa do yarn era congelar as dependências.

Isso reflete o comportamento do npm.
Você pode fazer yarn add [email protected] ou yarn add is-array --exact para a versão exata.
Talvez em algum momento devamos tornar padrão as versões exatas, isso pode ser uma discussão em um RFC.

Quando um pacote aleatório é excluído em node_modules, yarn install diz sucesso sem reinstalá-lo. Quando muitos deles acabam, ele os reinstala. O npm é um pouco mais completo a esse respeito.

O Yarn executa uma verificação superficial rápida por padrão.
Fazer uma verificação mais profunda será mais lento, mas estamos trabalhando nisso. Tenho uma ideia de como poderíamos fazer uma verificação profunda rápida.
Você não deve tocar nos arquivos em node_modules, porém, verificar cada arquivo para modificação resultaria em uma experiência de instalação muito lenta.
Se você quiser pular a verificação superficial, remova o arquivo node_modules/.yarn-integrity antes da instalação. Isso não é oficial e está sujeito a alterações.
Uma forma oficial é executar yarn install --force , isso forçaria a instalação completa, mas reescreveria yarn.lock como um efeito colateral.

O lockfile tende a ser regenerado se você deletar node_modules e fazer uma instalação limpa (que é literalmente o oposto do que você esperaria - eu espero que ele instale exatamente o que está no lockfile e não faça absolutamente nada mais)

Faz um tempo que não vejo isso.
Abra um problema e me envie uma cópia se ele puder ser reproduzido.

Se você deletar o lockfile sem tocar em package ou node_modules após uma instalação limpa, o yarn o regenera e é geralmente muito diferente da versão anterior. É como um compilador que produz um código diferente a cada vez que você o executa, apesar de não mudar nada.

Depois de algum tempo, novas versões de dependências transitivas podem ter sido lançadas.
Por causa disso, a estrutura de node_modules pode mudar significativamente por causa da lógica de içamento.
Isso funciona como planejado.
Há um comando import chegando em https://github.com/yarnpkg/yarn/pull/2580.
Isso permitiria a geração de um arquivo de bloqueio a partir de node_modules existentes.

@jspiro , Yarn é um projeto jovem voltado para a comunidade. Seus RPs para torná-lo um trabalho melhor para você são bem-vindos.

Alguma chance de obter pelo menos uma opção para definir o comportamento padrão desejado?

No momento, estamos corrigindo esse problema https://github.com/yarnpkg/yarn/issues/3490 , às vezes yarn install pode fazer com que o arquivo de bloqueio seja otimizado, o que não é um comportamento esperado e nós o consertaremos.
Essa pode ser a razão pela qual você está solicitando essa alteração, caso contrário, o arquivo yarn.lock deve ser alterado apenas se você fizer alterações no package.json manualmente.

Você pode definir --pure-lockfile / - frozen-lockfile como true em .yarnrc e será anexado ao comando de instalação por padrão:

--install.pure-lockfile true

Meu problema é que se eu não usar o pure-lockfile, obtenho a versão errada das dependências instaladas. Não está relacionado às alterações indesejadas do yarn.lock

Você pode enviar um problema com as etapas de reprodução?
Vamos resolver isso

Também fui mordido por isso quando package.json e yarn.lock saíram de sincronia devido a um desenvolvedor adicionar por engano uma dependência por meio de npm install --save vez de yarn add .

Eu discordo que pure-lockfile deve ser o padrão e argumento que frozen-lockfile deve ser o padrão para yarn install .

Como frozen-lockfile gerará uma mensagem de erro se yarn.lock e package.json estiverem fora de sincronia. O frozen-lockfile é, portanto, muito útil em uma máquina de construção (por exemplo, jenkins), pois marcará essas construções, como seria de se esperar, como uma falha.

Cabe então ao desenvolvedor decidir qual versão adicionar no package.json / yarn.lock.

O infeliz padrão de yarn install irá apenas buscar a versão mais atual das dependências ainda não bloqueadas e escrever uma versão atualizada yarn.lock , que nunca fará parte do projeto. Portanto, permitindo quebras futuras da construção devido a um aumento inesperado da versão. Essa é a razão pela qual temos um arquivo de bloqueio para começar.

A essência deve ser:

Apenas comandos como add , remove e upgrade devem transformar yarn.lock .

install deve apenas fazer isso, ou seja, instalar as dependências em sua versão bloqueada ou falhar se detectar uma incompatibilidade entre package.json e yarn.lock . (A única exceção é se não houver yarn.lock em primeiro lugar. Então, e somente então, ele pode criar um, mas nunca, nunca deve tocá-lo novamente.)

O arquivo frozen-lock é, portanto, muito útil na máquina de construção (ou seja, jenkins), pois essas construções irão falhar.

Acho que podemos habilitar isso automaticamente quando detectarmos que estamos no modo CI?

@BYK Não sabia que este problema estava

Eu diria para abrir um novo ☺️

Eu concordo com @thejameskyle e @kittens que yarn.lock deve ser mantido em sincronia com o package.json automaticamente

Não tenho certeza se isso foi dito, mas apenas no caso: você não precisa invalidar todo o yarn.lock quando algo em package.json mudar. Você pode invalidar apenas as dependências de pacotes que foram modificados dentro de package.json. Por exemplo, se você atualizou apenas o TypeScript, as dependências do TypeScript precisariam ser modificadas (com considerações a respeito de outros pacotes inalterados).

Esta página foi útil?
0 / 5 - 0 avaliações