Perché "npm install" riscrive package-lock.json?


614

Ho appena aggiornato a npm @ 5 . Ora ho un file package-lock.json con tutto da package.json . Mi aspetto che, quando eseguo,npm install le versioni di dipendenza vengano estratte dal file di blocco per determinare cosa dovrebbe essere installato nella mia directory node_modules . La cosa strana è che finisce per modificare e riscrivere il mio file package-lock.json .

Ad esempio, nel file di blocco è stato specificato il dattiloscritto nella versione 2.1.6 . Quindi, dopo il npm installcomando, la versione è stata modificata in 2.4.1 . Ciò sembra vanificare l'intero scopo di un file di blocco.

Cosa mi sto perdendo? Come faccio a ottenere npm per rispettare effettivamente il mio file di blocco?


4
Questo non risponde alla tua domanda, quindi speriamo che un commento sia ok, ma dai un'occhiata a Yarn. Il passaggio ha richiesto meno di un'ora per noi.
KayakinKoder,

4
Lo stesso problema, ma usando il filo github.com/yarnpkg/yarn/issues/570 (molto istruttivo)
Yves M.

2
Sto avendo lo stesso problema. Il mio package-lock.jsonviene rigenerato quando corro npm install. Questo ha l'odore di un bug npm. Usi il tuo registro?
HaNdTriX,


@YvesM. --no-saveimpedisce di modificare il file di blocco, ma non influisce sull'insensato aggiornamento di dipendenza di primo livello menzionato dall'OP.
Ross Allen

Risposte:


423

Aggiornamento 3: Come sottolineato anche da altre risposte, il npm cicomando è stato introdotto in npm 5.7.0 come ulteriore modo per ottenere build veloci e riproducibili nel contesto CI. Vedere la documentazione e il blog npm per ulteriori informazioni.


Aggiornamento 2: il problema per aggiornare e chiarire la documentazione è il problema n . 18103 di GitHub .


Aggiornamento 1: il comportamento descritto di seguito è stato risolto in npm 5.4.2: il comportamento attualmente previsto è delineato nel numero # 17979 di GitHub .


Risposta originale: il comportamento di è package-lock.jsonstato modificato in npm 5.1.0 come discusso nel numero # 16866 . Il comportamento che si osserva è apparentemente inteso da npm a partire dalla versione 5.1.0.

Ciò significa che package.jsonpuò eseguire l'override package-lock.jsonogni volta che viene trovata una versione più recente per una dipendenza in package.json. Se si desidera bloccare in modo efficace le proprie dipendenze, è ora necessario specificare le versioni senza prefisso, ad esempio, è necessario scriverle come 1.2.0anziché ~1.2.0o ^1.2.0. Quindi la combinazione di package.jsone package-lock.jsonprodurrà build riproducibili. Per essere chiari: package-lock.jsonda solo non blocca più le dipendenze a livello di root!

Se questa decisione di progettazione è stata buona o no è discutibile, c'è una discussione in corso risultante da questa confusione su GitHub nel numero # 17979 . (Ai miei occhi è una decisione discutibile; almeno il nome locknon è più vero.)

Un'altra nota a margine: esiste anche una restrizione per i registri che non supportano i pacchetti immutabili, come quando si estraggono i pacchetti direttamente da GitHub anziché da npmjs.org. Vedere questa documentazione dei blocchi dei pacchetti per ulteriori spiegazioni.


43
A cosa serve l'hack npm updateallora? : o Ho avuto la stessa sensazione che ha npm installaggiornato deps, ma non voglio crederci .. ma sembra che sia tristemente vero .. Comunque c'è ancora un'opzione da usare npm shrinkwrapper bloccare i deps, ma sicuramente il nome di package-lock non è corretto in quanto non congela, né blocca le dipendenze ..
Jurosh

266
Che casino! Il gestore di pacchetti più grande del mondo non ha ancora documentazione su come dovrebbe funzionare. Ognuno sta indovinando cosa dovrebbe fare e si trasforma in una guerra di opinioni. La discussione è buona ma dovrebbe avvenire prima di un rilascio in libertà. A un certo punto qualcuno deve effettuare la chiamata finale e quindi può essere implementato, documentato e rilasciato. PHP è stato progettato dal comitato e messo insieme ad hoc e guarda come è venuto fuori. Odierei vedere accadere la stessa cosa a uno strumento così critico e ampiamente usato.
Landon Poch,

85
Quindi, qual è lo scopo di usare package-lock? Pensavo che avrebbe creato lo stesso ambiente in diverse aree di lavoro, ma si scopre che non sta facendo nulla
laltin,

17
"Quindi la combinazione di package.json e package-lock.json produrrà build riproducibili." Che ruolo ha "package-lock.json" qui? "Package.json" da solo non produce già build riproducibili se non vengono utilizzati prefissi di versione?
Jānis Elmeris,

12
@ JānisElmeris Penso che package.json non riesca a bloccare le dipendenze profonde ...
Juan Mendes,

165

Ho scoperto che ci sarà una nuova versione di npm 5.7.1 con il nuovo comando npm ci, che verrà installata package-lock.jsonsolo da

Il nuovo comando npm ci viene installato SOLO dal file di blocco. Se package.json e il file di blocco non sono sincronizzati, verrà segnalato un errore.

Funziona gettando via i tuoi node_modules e ricreandoli da zero.

Oltre a garantirti che otterrai solo ciò che è nel tuo file di blocco, è anche molto più veloce (2x-10x!) Rispetto all'installazione di npm quando non inizi con un node_modules.

Come puoi prendere dal nome, ci aspettiamo che sia un grande vantaggio per gli ambienti di integrazione continua. Ci aspettiamo anche che le persone che eseguono distribuzioni di produzione dai tag git vedranno grandi guadagni.


133
Questo dovrebbe essere il comportamento predefinito se esiste un file di blocco.
nullability

13
Quindi hanno cambiato il funzionamento di npm, solo per riportarlo come npm ci mesi dopo?
Scott Flack,

1
Sono ancora confuso. La documentazione dice "Assicurati di avere un blocco dei pacchetti e un'installazione aggiornata: npm install" prima di eseguire il comando npm ciin quel progetto. Non npm installsovrascrive il file package-lock.json?
adiga,

1
AFAIK: @adiga - a partire dalla versione 5.4, modifica il file di blocco npm solo se necessario per farlo, per soddisfare le specifiche in pacchetti.json . Quindi, se i pacchetti erano soliti dire thatpackage: 1, e lock dice ..: 1.0.4, dev può modificare per dire thatpackage: 2- e questo forzerà il cambiamento del file lock, perché 1.0.4non è compatibile con l'intervallo appena specificato. In caso contrario packages.json, rimarrà bloccato alla versione esatta, fino all'eliminazione del file di blocco. [Se non rimane bloccato e non ha cambiato
package.json

1
@George Dalle informazioni che ho letto (per le versioni recenti di npm) e dai miei test limitati: sì ad entrambi.
Venryx,

95

Usa il nuovo introdotto

npm ci

npm ci promette il massimo beneficio per i team di grandi dimensioni. Dare agli sviluppatori la possibilità di "firmare" su un blocco dei pacchetti promuove una collaborazione più efficiente tra i team di grandi dimensioni e la possibilità di installare esattamente ciò che si trova in un file di blocco ha il potenziale per salvare decine se non centinaia di ore di sviluppo al mese, liberando i team per dedicare più tempo alla costruzione e alla spedizione di cose straordinarie.

Presentazione npm cidi build più veloci e affidabili


3
questo mi sembra corretto? qualcun altro può confermare?
phouse512,

6
@ phouse512 Questo è corretto. Abbiamo praticamente solo usiamo npm ci, e utilizzare solo npm installse l'aggiornamento o l'installazione di nuovi pacchetti.
Jacob Sievers,

1
Commenti recenti, ecc. Questa è la risposta con cui sto andando. Peccato che non possano risolvere l'orribile snafu, ma se il nuovo vangelo è "npm ci", allora va bene. Posso adattarmi.
Svend

Peccato che elimina sempre una node_modulesdirectory esistente e la ricostruisce localmente, anche se si tratta di un link simbolico altrimenti vuoto ma importante. :(
Joe Atzberger,

2
@ToolmakerSteve Non trattenere il respiro! Penso che cancellare il contenuto di una directory sia molto più lento della semplice cancellazione della directory. Dovresti enumerare i contenuti, quindi emettere una serie di comandi di eliminazione anziché solo il comando di eliminazione nell'O / S. Con i problemi di prestazioni precedentemente livellati a npm e il miglioramento che utilizzo, npm cimi aspetto che siano molto riluttanti a introdurre qualsiasi cosa che possa ridurre le prestazioni per un caso d'uso piuttosto insolito. Potresti voler dare un'occhiata a pnpm.js.org anche se questo fa uso di hard link per ridurre l'utilizzo del disco.
Caltor,

64

Risposta breve:

  • npm install onora package-lock.json solo se soddisfa i requisiti di package.json.
  • Se non soddisfa tali requisiti, i pacchetti vengono aggiornati e il blocco dei pacchetti viene sovrascritto.
  • Se invece non riesci a compilare, piuttosto che riscrivere il blocco dei pacchetti quando ciò accade, usa npm ci.

Ecco uno scenario che potrebbe spiegare le cose (verificato con NPM 6.3.0)

Dichiarate una dipendenza in package.json come:

"depA": "^1.0.0"

Quindi lo fai, npm installche genererà un pacchetto-lock.json con:

"depA": "1.0.0"

Pochi giorni dopo, viene rilasciata una versione minore di "depA", ad esempio "1.1.0", quindi vale quanto segue:

npm ci       # respects only package-lock.json and installs 1.0.0

npm install  # also, respects the package-lock version and keeps 1.0.0 installed 
             # (i.e. when package-lock.json exists, it overrules package.json)

Successivamente, aggiorni manualmente package.json a:

"depA": "^1.1.0"

Quindi rieseguire:

npm ci      # will try to honor package-lock which says 1.0.0
            # but that does not satisfy package.json requirement of "^1.1.0" 
            # so it would throw an error 

npm install # installs "1.1.0" (as required by the updated package.json)
            # also rewrites package-lock.json version to "1.1.0"
            # (i.e. when package.json is modified, it overrules the package-lock.json)

4
Questo è in effetti il ​​comportamento previsto di un file "lock". Apparentemente, non era il caso delle versioni precedenti di NPM.
Blockost,

1
Quindi in che modo npm tiene traccia dell'ultimo aggiornamento su package.json? Cosa succede quando sposti package.json e package-lock.json su un altro computer? Come fa npm nel nuovo computer a sapere se package.lock è quello originale o è stato aggiornato, per decidere se deve aggiornare package-lock.json o no?
Lahiru Chandima,

3
@LahiruChandima Non tiene traccia degli aggiornamenti. npm installutilizzerà le versioni bloccate a package-lock.jsonmeno che non soddisfi il package.jsoncaso in cui installi package.json e ricostruisca package-lock.json di conseguenza. Se hai modificato il tuo package.jsonin modo tale che il blocco dei pacchetti esistente soddisfi ancora l'aggiornamento package.json, continuerà a usarlopackage-lock
Ahmad Abdelghany,

1
Se hai già un modulo in node_modules che soddisfa i requisiti di package.json, allora npm installnon fa nulla, indipendentemente da package-lock.json. Dobbiamo aggiornare esplicitamente i pacchetti anche quando sono disponibili aggiornamenti che corrispondono al semver specificato in package.json. Almeno questa è stata la mia esperienza per anni.
carlin.scott,

1
@ToolmakerSteve Ero anche scettico sul comportamento segnalato da @ carlin.scott, ma l'ho appena testato, e in effetti è corretto. Se la versione all'interno node_modulessoddisfa l'intervallo package.jsone non è presente alcun package-lock.jsonfile, npm non aggiornerà il modulo durante l'esecuzione npm install. Immagino che vada bene dato che puoi usare npm update(o npm-checkper ultimo) per aggiornare le dipendenze, e questo comportamento è più veloce nel caso in cui qualcuno aggiunga solo una voce package.jsone non desideri che i pacchetti non correlati si aggiornino all'ultimo che soddisfa il sem-ver gamma.
Venryx,

19

Utilizzare il npm cicomando anziché npm install.

"ci" sta per "integrazione continua".

Installerà le dipendenze del progetto in base al file package-lock.json anziché alle dipendenze del file lenient package.json.

Produrrà build identiche ai tuoi compagni di squadra ed è anche molto più veloce.

Puoi leggere di più a riguardo in questo post del blog: https://blog.npmjs.org/post/171556855892/introducing-npm-ci-for-faster-more-reliable


2
cifa riferimento alla "integrazione continua", come menzionato nei documenti e nel post sul blog che annunciano il comando: blog.npmjs.org/post/171556855892/…
Joe Atzberger,

Grazie Joe. Ho aggiornato la mia risposta con il nome corretto e collegata al post del blog. 😊 (per chi legge questo, in precedenza ho detto che sta per "installazione pulita")
Daniel Tonon,

"Ed è anche molto più veloce": eliminerà la node_modulescartella e la creerà da zero. È davvero molto più veloce? Fa npm installeliminazione node_modulesdella cartella, troppo?
izogfif,

Penso che la velocità provenga da npm che non ha bisogno di calcolare quali pacchetti scaricare. Pensaci come se npm installdovesse risolvere tutte le dipendenze del pacchetto quando eseguito. npm ciè solo una lista della spesa per "ottenere questi moduli esatti".
Daniel Tonon,

8

In futuro, sarai in grado di utilizzare un --from-lock-fileflag (o simile) per installare solo da package-lock.jsonsenza modificarlo.

Ciò sarà utile per ambienti CI, ecc. In cui le build riproducibili sono importanti.

Consulta https://github.com/npm/npm/issues/18286 per il monitoraggio della funzione.


Ne dubito. In che modo se le dipendenze sono diverse per i diversi sistemi operativi, come si può forzare l'installazione di qualcosa che non funzionerebbe?
Yevgeniy Afanasyev,

4
@YevgeniyAfanasyev Invece di quella bandiera, è stata implementata in quanto npm cigestisce anche la tua domanda.
spex

8

Sembra che questo problema sia stato risolto in npm v5.4.2

https://github.com/npm/npm/issues/17979

(Scorri verso il basso fino all'ultimo commento nel thread)

Aggiornare

Corretto effettivamente in 5.6.0. Si è verificato un errore multipiattaforma in 5.4.2 che causava ancora il problema.

https://github.com/npm/npm/issues/18712

Aggiornamento 2

Vedi la mia risposta qui: https://stackoverflow.com/a/53680257/1611058

npm ci è il comando che dovresti usare quando installi progetti esistenti adesso.


5
Sto usando 5.4.2 e mi risulta ancora la modifica del mio pacchetto-lock.json quando npm i. Ad esempio, il modulo fseventsviene rimosso quando mi trovo npm isu una macchina che non supporta fseventse quindi il modulo viene nuovamente aggiunto quando uno npm isu una macchina che lo supporta .
hrdwdmrbl,

Quindi dovresti sollevare un nuovo problema nel repository npm GitHub che spiega questo. Se non funziona come dicono che dovrebbe funzionare, lo vedono come un bug ad alta priorità che deve essere risolto urgentemente.
Daniel Tonon,

@hrdwdmrbl sto vedendo lo stesso fseventscalo di mia package-lock.jsoncon npm@5.5collaborando con Mac OS X collaboratori. Se non hai aperto un problema, lo farò.
AL il

@hrdwdmrbl Ho scoperto che (e il lungo thread di problemi associati) dopo aver lasciato il mio commento e ho dimenticato di tornare a SO per aggiornare il mio commento. Grazie per avermi riavuto. Va tutto bene.
AL il X

4

Probabilmente hai qualcosa del tipo:

"typescript":"~2.1.6"

nel package.jsonquale npm si aggiorna all'ultima versione minore, nel tuo caso2.4.1

Modifica: domanda dall'OP

Ma ciò non spiega perché "npm install" cambierebbe il file di blocco. Il file di blocco non è pensato per creare una build riproducibile? In tal caso, indipendentemente dal valore del semver, dovrebbe comunque utilizzare la stessa versione 2.1.6.

Risposta:

Questo ha lo scopo di bloccare l'intero albero delle dipendenze. Diciamo che typescript v2.4.1richiede widget ~v1.0.0. Quando si installa npm lo prende widget v1.0.0. Successivamente il tuo collega sviluppatore (o build CI) esegue un'installazione npm e ottiene typescript v2.4.1ma widgetè stato aggiornato a widget v1.0.1. Ora il tuo modulo nodo non è sincronizzato. Questo è ciò che package-lock.jsonimpedisce.

O più in generale:

Ad esempio, considera

pacchetto A:

{"name": "A", "version": "0.1.0", "dependencies": {"B": "<0.1.0"}}

pacchetto B:

{"name": "B", "version": "0.0.1", "dependencies": {"C": "<0.1.0"}}

e pacchetto C:

{"name": "C", "version": "0.0.1"}

Se queste sono le uniche versioni di A, B e C disponibili nel registro, verrà installata una normale installazione npm A:

A@0.1.0 - B@0.0.1 - C@0.0.1

Tuttavia, se viene pubblicato B@0.0.2, verrà installata una nuova installazione npm A:

A@0.1.0 - B@0.0.2 - C@0.0.1 supponendo che la nuova versione non abbia modificato le dipendenze di B. Naturalmente, la nuova versione di B potrebbe includere una nuova versione di C e un numero qualsiasi di nuove dipendenze. Se tali modifiche sono indesiderabili, l'autore di A potrebbe specificare una dipendenza da B@0.0.1. Tuttavia, se l'autore di A e l'autore di B non sono la stessa persona, non c'è modo per l'autore di dire che non vuole inserire le versioni di C pubblicate di recente quando B non è cambiato affatto.


Domanda OP 2: Fammi vedere se ho capito bene. Quello che stai dicendo è che il file lock specifica le versioni delle dipendenze secondarie, ma si basa ancora sulla corrispondenza fuzzy di package.json per determinare le dipendenze di livello superiore. È preciso?

Risposta: No. package-lock blocca l'intero albero dei pacchetti, inclusi i pacchetti root descritti in package.json. Se typescriptè bloccato 2.4.1nel tuo package-lock.json, dovrebbe rimanere tale fino a quando non viene modificato. E diciamo che domani typescriptrilascia la versione 2.4.2. Se controllo il tuo ramo ed npm installeseguo, npm rispetterà il file di blocco e l'installazione 2.4.1.

Maggiori informazioni su package-lock.json:

package-lock.json viene generato automaticamente per qualsiasi operazione in cui npm modifica l'albero node_modules o package.json. Descrive l'albero esatto che è stato generato, in modo che le installazioni successive siano in grado di generare alberi identici, indipendentemente dagli aggiornamenti di dipendenza intermedi.

Questo file è destinato al commit nei repository di origine e serve a vari scopi:

Descrivere una singola rappresentazione di un albero delle dipendenze in modo tale che i compagni di squadra, le distribuzioni e l'integrazione continua possano installare esattamente le stesse dipendenze.

Fornire agli utenti la possibilità di "viaggiare nel tempo" verso gli stati precedenti di node_modules senza dover eseguire il commit della directory stessa.

Per facilitare una maggiore visibilità delle modifiche dell'albero mediante differenze di controllo della sorgente leggibili.

E ottimizza il processo di installazione consentendo a npm di saltare ripetute risoluzioni dei metadati per i pacchetti precedentemente installati.

https://docs.npmjs.com/files/package-lock.json


29
Ma ciò non spiega perché "npm install" cambierebbe il file di blocco. Il file di blocco non è pensato per creare una build riproducibile? In tal caso, indipendentemente dal valore del semver, dovrebbe comunque utilizzare la stessa versione 2.1.6.
Viper Bailey,

3
E questa è la cosa che sto dicendo. Il mio file di blocco del pacchetto dice typescript@2.1.6 ma quando eseguo npm install, la voce viene sostituita con typescript@2.4.1.
Viper Bailey,

5
Ho riscontrato questo stesso problema. Nel nostro CI / CD, package-lock.jsonviene rimosso e quindi eseguito npm install, ma il package-lock.jsonfile viene modificato e dobbiamo eseguire un ripristino prima di poter eseguire le modifiche successive.
BayssMekanique,

15
Non capisco In che modo si tratta di un file di "blocco" se le installazioni successive potrebbero ancora eseguire aggiornamenti ?!
Ross Allen

5
Penso che abbiano iniziato con l'idea di avere questo file come "info" e "lock" e poi, hanno deciso che sarà solo un file "info". Il nome migliore sarebbe "pacchetto-info.json". Mi piacerebbe avere un "npm install -lock" che verrà installato da "package-lock.json" e ignorato "package.json"
Jeremy Chone,

2

Probabilmente dovresti usare qualcosa del genere

npm ci

Invece di utilizzare npm install se non si desidera modificare la versione del pacchetto.

Secondo la documentazione ufficiale, entrambi npm installe npm ciinstallare le dipendenze necessarie per il progetto.

La differenza principale è npm installche installa i pacchetti prendendo packge.jsoncome riferimento. Dove nel caso di npm ci, installa i pacchetti prendendo package-lock.jsoncome riferimento, assicurandosi ogni volta che viene installato il pacchetto esatto.



0

EDIT: il nome "lock" è difficile, il suo NPM sta cercando di raggiungere Yarn. Non è assolutamente un file bloccato. package.jsonè un file corretto dall'utente, che una volta "installato" genererà l'albero delle cartelle node_modules e tale albero verrà quindi scritto package-lock.json. Come vedi, è il contrario: le versioni delle dipendenze verranno estratte package.jsoncome sempre e package-lock.jsondovrebbero essere chiamatepackage-tree.json

(spero che questo abbia reso la mia risposta più chiara, dopo così tanti voti negativi)


Una risposta semplicistica: package.jsonavere le proprie dipendenze come al solito, mentre package-lock.jsonè "un albero node_modules esatto e, soprattutto, riproducibile" (preso dagli stessi documenti di npm ).

Per quanto riguarda il nome difficile, il suo NPM sta cercando di raggiungere Yarn.


1
Perché se si esegue npm install, il blocco dei pacchetti verrà aggiornato.
Jean-Baptiste,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.