Dlaczego program „npm install” przepisuje pakiet-lock.json?

612

Niedawno zaktualizowałem do npm @ 5 . Mam teraz plik package-lock.json ze wszystkim z pliku package.json . Spodziewałbym się, że po uruchomieniu npm installwersje zależności zostaną wyciągnięte z pliku blokady, aby określić, co powinno zostać zainstalowane w moim katalogu node_modules . Dziwne jest to, że w rzeczywistości modyfikuje i przepisuje mój plik package-lock.json .

Na przykład w pliku blokady określono maszynopis w wersji 2.1.6 . Następnie po npm installpoleceniu zmieniono wersję na 2.4.1 . Wydaje się, że pokonuje to cały cel pliku blokady.

czego mi brakuje? Jak mogę zmusić npm do respektowania mojego pliku blokady?

Viper Bailey
źródło
4
To nie odpowiada na twoje pytanie, więc mam nadzieję, że komentarz jest w porządku, ale spójrz na Yarn. Zmiana zajęła nam mniej niż godzinę.
KayakinKoder,
4
Ten sam problem, ale przy użyciu przędzy github.com/yarnpkg/yarn/issues/570 (bardzo pouczające)
Yves M.,
2
Mam ten sam problem. Moja package-lock.jsonregeneruje się po uruchomieniu npm install. Pachnie jak błąd npm. Czy korzystasz z własnego rejestru?
HaNdTriX
@YvesM. --no-savezapobiega zmianie pliku blokującego, ale nie wpływa na niemądre uaktualnianie zależności pierwszego poziomu, o którym wspomina PO.
Ross Allen

Odpowiedzi:

422

Aktualizacja 3: Jak wskazują inne odpowiedzi, npm cipolecenie zostało wprowadzone w npm 5.7.0 jako dodatkowy sposób na szybkie i powtarzalne kompilacje w kontekście CI. Więcej informacji znajduje się w dokumentacji i blogu npm .


Aktualizacja 2: Problemem do aktualizacji i wyjaśnienia dokumentacji jest problem GitHub nr 18103 .


Aktualizacja 1: Zachowanie, które zostało opisane poniżej, zostało naprawione w npm 5.4.2: aktualnie planowane zachowanie jest opisane w numerze GitHub # 17979 .


Oryginalna odpowiedź: zachowanie programu package-lock.jsonzostało zmienione w npm 5.1.0, jak omówiono w numerze # 16866 . Zachowanie, które obserwujesz, jest najwyraźniej zamierzone przez npm od wersji 5.1.0.

Oznacza to, że package.jsonmoże to zastąpić package-lock.jsonza każdym razem, gdy zostanie znaleziona nowsza wersja dla zależności w package.json. Jeśli chcesz skutecznie przypiąć swoje zależności, musisz teraz określić wersje bez prefiksu, np. Musisz je zapisać jako 1.2.0zamiast ~1.2.0lub ^1.2.0. Następnie kombinacja package.jsoni package-lock.jsonda powtarzalne kompilacje. Żeby było jasne: package-lock.jsonsam nie blokuje już zależności poziomu root!

To, czy ta decyzja projektowa była dobra, czy nie, jest dyskusyjne, toczy się dyskusja wynikająca z tego zamieszania na GitHubie w numerze 17979 . (Moim zdaniem jest to wątpliwa decyzja; przynajmniej nazwa locknie jest już prawdą).

Jeszcze jedna uwaga: istnieje również ograniczenie dla rejestrów, które nie obsługują niezmiennych pakietów, na przykład gdy pobierasz pakiety bezpośrednio z GitHub zamiast npmjs.org. Więcej informacji można znaleźć w tej dokumentacji blokad opakowań .

jotaen
źródło
43
Do czego służy hack npm update? : o Mam takie samo przeczucie, że npm installzaktualizowałem deps, ale nie chcę w to uwierzyć ... ale wydaje się, że to niestety prawda. W każdym razie nadal istnieje opcja npm shrinkwrapblokowania deps, ale zdecydowanie nazwa pakietu-lock jest niepoprawna ponieważ nie zamraża ani nie blokuje zależności.
Jurosh
266
Co za bałagan! Największy na świecie menedżer pakietów, ale nie ma dokumentacji, jak powinien działać. Wszyscy zgadują, co powinien zrobić, a to zamienia się w wojnę opinii. Dyskusja jest dobra, ale powinna się odbyć przed wypuszczeniem na wolność. W pewnym momencie ktoś musi wykonać ostatnie połączenie, a następnie może zostać wdrożony, udokumentowany i zwolniony. PHP zostało opracowane wspólnie przez komitet i ad-hoc'd i spójrz, jak się okazało. Nienawidzę patrzeć, jak to samo dzieje się z tak krytycznym i szeroko stosowanym narzędziem.
Landon Poch
85
W takim razie po co używać blokady pakietu? Myślałem, że stworzy to samo środowisko w różnych
obszarach
17
„Wówczas połączenie package.json i package-lock.json da powtarzalne kompilacje.” Jaką rolę ma tutaj „package-lock.json”? Czy sam plik „package.json” już nie zapewnia powtarzalnych kompilacji, jeśli nie zostaną użyte prefiksy wersji?
Jānis Elmeris
12
@ JānisElmeris Myślę, że package.json nie może zablokować głębokich zależności ...
Juan Mendes,
165

Odkryłem, że będzie nowa wersja npm 5.7.1 z nowym poleceniem npm ci, które będzie instalować package-lock.jsontylko z

Nowa komenda npm ci instaluje się TYLKO z pliku blokady. Jeśli plik package.json i plik blokady nie są zsynchronizowane, zgłosi błąd.

Działa poprzez wyrzucenie modułów node_modules i odtworzenie ich od zera.

Oprócz zagwarantowania, że ​​dostaniesz tylko to, co znajduje się w pliku blokady, jest także znacznie szybszy (2x-10x!) Niż instalacja npm, jeśli nie zaczynasz od modułów node_module.

Jak sama nazwa wskazuje, spodziewamy się, że będzie to duży dar dla ciągłej integracji środowisk. Oczekujemy również, że ludzie, którzy wykonają wdrożenia produkcyjne z tagów git, zobaczą znaczne korzyści.

Ivan Shcherbakov
źródło
133
To powinno być zachowanie domyślne, jeśli istnieje plik blokujący.
nullability
13
Więc zmienili sposób działania npm i tylko po to, by przywrócić go jako npm ci miesiące później?
Scott Flack
1
Wciąż jestem zdezorientowany. Dokumentacja mówi „Upewnij się, że masz pakiet-lock i aktualną instalację: npm install przed uruchomieniem polecenia npm ciw tym projekcie. Czy nie npm installzastępuje pliku package-lock.json?
adiga
1
AFAIK: @adiga - począwszy od wersji 5.4, zmienia npm tylko plik blokady, jeśli jest to konieczne, aby spełnić specyfikację w Package.json . Więc jeśli pakiety mówiły thatpackage: 1, a blokada mówi ..: 1.0.4, dev może edytować, aby powiedzieć thatpackage: 2- i to zmusi plik blokady do zmiany, ponieważ 1.0.4nie jest zgodny z nowo określonym zakresem. Jeśli się nie zmieni packages.json, pozostanie zablokowany na dokładnej wersji, aż do usunięcia pliku blokady. [Jeśli nie pozostaje zamknięty i nie zmienia pliku Package.json, zgłoś raport o błędzie.]
ToolmakerSteve
1
@George Z informacji, które przeczytałem (dla ostatnich wersji npm) i moich ograniczonych testów: tak dla obu.
Venryx,
95

Użyj nowo wprowadzonego

npm ci

npm ci obiecuje największe korzyści dużym zespołom. Umożliwienie programistom „wylogowania się” z blokady pakietu sprzyja wydajniejszej współpracy między dużymi zespołami, a możliwość zainstalowania dokładnie tego, co znajduje się w pliku blokady, może potencjalnie zaoszczędzić dziesiątki, jeśli nie setki godzin programistów w miesiącu, uwalniając zespoły spędzać więcej czasu na budowaniu i wysyłaniu niesamowitych rzeczy.

Przedstawiamy npm ciszybsze, bardziej niezawodne kompilacje

Gal Margalit
źródło
3
wydaje mi się to poprawne? czy ktoś inny może potwierdzić?
phouse512
6
@ phouse512 To prawda. Prawie używamy tylkonpm ci i tylko npm installwtedy, gdy aktualizujemy lub instalujemy nowe pakiety.
Jacob Sievers,
1
Najnowsze komentarze itp. Oto odpowiedź, z którą idę. Szkoda, że ​​nie mogą naprawić strasznego snafu, ale jeśli nową ewangelią jest „npm ci”, to dobrze. Mogę się dostosować.
Svend
Szkoda, że zawsze usuwa istniejący node_moduleskatalog i odbudowuje lokalnie, nawet jeśli jest to inaczej puste, ale ważne dowiązanie symboliczne. :(
Joe Atzberger
2
@ToolmakerSteve Nie wstrzymuj oddechu! Myślę, że usunięcie zawartości katalogu byłoby o wiele wolniejsze niż samo usunięcie katalogu. Trzeba wyliczyć zawartość, a następnie wydać O / S szereg poleceń usuwania, a nie tylko jedno polecenie usuwania. Z problemami z wydajnością poprzednio wyrównywanymi na npm i poprawą przy użyciu npm ci, spodziewam się, że byliby bardzo niechętni do wprowadzenia czegokolwiek, co mogłoby obniżyć wydajność w dość rzadkim przypadku użycia. Możesz jednak sprawdzić stronę pnpm.js.org, która korzysta z twardych łączy w celu zmniejszenia zużycia dysku.
Caltor,
64

Krótka odpowiedź:

  • npm install honoruje pakiet-lock.json tylko wtedy, gdy spełnia wymagania określone w pakiecie.json.
  • Jeśli nie spełnia tych wymagań, pakiety są aktualizowane, a pakiet-lock jest zastępowany.
  • Jeśli wolisz kompilację, niż przepisz pakiet-lock, kiedy to się stanie, użyj npm ci.

Oto scenariusz, który może wyjaśniać różne rzeczy (Verified with NPM 6.3.0)

Deklarujesz zależność w pakiecie.json jak:

"depA": "^1.0.0"

Następnie zrobisz, npm installco wygeneruje pakiet-lock.json z:

"depA": "1.0.0"

Kilka dni później zostaje wydana nowsza, mniejsza wersja „depA”, powiedzmy „1.1.0”, a następnie spełnione są następujące warunki:

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)

Następnie ręcznie zaktualizuj plik package.json do:

"depA": "^1.1.0"

Następnie uruchom ponownie:

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)
Ahmad Abdelghany
źródło
4
Jest to rzeczywiście zamierzone zachowanie pliku „blokady”. Najwyraźniej nie było tak w przypadku starszych wersji NPM.
Blockost
1
Więc w jaki sposób npm śledzi ostatnią aktualizację do package.json? Co się stanie, gdy przeniesiesz pakiet package.json i package-lock.json na inny komputer? Skąd npm na nowym komputerze wie, czy pakiet.lock jest oryginalny, czy został zaktualizowany, aby zdecydować, czy należy zaktualizować pakiet-lock.json, czy nie?
Lahiru Chandima,
3
@LahiruChandima To tak naprawdę nie śledzi aktualizacji. npm installużyje zablokowanych wersji, package-lock.jsonchyba że nie spełnia warunków, package.jsonw których to instaluje pakiet.json i odpowiednio przebudowuje pakiet-lock.json. Jeśli zmieniłeś swój package.jsonw taki sposób, że istniejąca blokada pakietu nadal spełnia wymagania zaktualizowanej wersji package.json, nadal będzie go używaćpackage-lock
Ahmad Abdelghany
1
Jeśli masz już moduł w module node_modules, który spełnia wymagania package.json, to npm installnic nie robi, niezależnie od package-lock.json. Musimy jawnie aktualizować pakiety, nawet jeśli są dostępne aktualizacje, które pasują do semver określonego w package.json. Przynajmniej takie było moje doświadczenie od lat.
carlin.scott
1
@ToolmakerSteve Byłem także sceptycznie nastawiony do zachowania, które zgłosił @ carlin.scott, ale właśnie to przetestowałem i faktycznie ma rację. Jeśli wersja node_modulesmieści się w zakresie package.jsoni nie ma package-lock.jsonpliku, npm nie zaktualizuje modułu podczas działania npm install. Wydaje mi się, że jest w porządku, ponieważ można użyć npm update(lub npm-checknajnowszej) do aktualizacji zależności, a to zachowanie jest szybsze w przypadku kogoś, kto po prostu dodaje jeden wpis package.jsoni nie chce, aby niepowiązane pakiety aktualizowały się do najnowszej wersji, która spełnia sem-ver zasięg.
Venryx,
19

Użyj npm cipolecenia zamiast npm install.

„ci” oznacza „ciągłą integrację”.

Zainstaluje zależności projektu na podstawie pliku package-lock.json zamiast łagodnych zależności pliku package.json.

Będzie produkować identyczne kompilacje z członkami twojej drużyny, a także jest znacznie szybszy.

Możesz przeczytać więcej na ten temat w tym poście na blogu: https://blog.npmjs.org/post/171556855892/introducing-npm-ci-for-faster-more-reliable

Daniel Tonon
źródło
2
ciodnosi się do „ciągłej integracji”, jak wspomniano w dokumentach i poście na blogu, ogłaszając polecenie: blog.npmjs.org/post/171556855892/…
Joe Atzberger,
Dzięki Joe. Zaktualizowałem swoją odpowiedź poprawną nazwą i umieściłem link do postu na blogu. 😊 (dla osób, które to czytają, wcześniej powiedziałem, że oznacza „czystą instalację”)
Daniel Tonon
„I jest także znacznie szybszy” - usunie node_modulesfolder i odtworzy go od zera. Czy to naprawdę dużo szybsze? Czy npm installusuwa także node_modulesfolder?
izogfif
Myślę, że prędkość pochodzi z npm, który nie musi obliczać pakietów do pobrania. Pomyśl o tym jaknpm install trzeba rozwiązać wszystkie zależności pakietu po uruchomieniu. npm cito tylko lista zakupów „pobierz te dokładne moduły”.
Daniel Tonon
8

W przyszłości będziesz mógł użyć --from-lock-fileflagi (lub podobnej), aby zainstalować tylko z poziomu package-lock.jsonbez jej modyfikowania.

Będzie to przydatne w środowiskach CI itp., W których ważne są odtwarzalne kompilacje.

Zobacz https://github.com/npm/npm/issues/18286 w celu śledzenia funkcji.

Timothy Higinbottom
źródło
Wątpię. Co zrobić, jeśli zależności są różne dla różnych systemów operacyjnych, w jaki sposób można wymusić instalację czegoś, co nie działa?
Jewgienij Afanasiew
4
@YevgeniyAfanasyev Zamiast tej flagi, została zaimplementowana jako, npm ciktóra obsługuje również twoje pytanie.
spex
8

Wygląda na to, że ten problem został rozwiązany w npm v5.4.2

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

(Przewiń w dół do ostatniego komentarza w wątku)

Aktualizacja

Naprawiono w wersji 5.6.0. W wersji 5.4.2 wystąpił błąd wieloplatformowy, który powodował, że problem nadal występował.

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

Aktualizacja 2

Zobacz moją odpowiedź tutaj: https://stackoverflow.com/a/53680257/1611058

npm ci to polecenie, którego powinieneś używać podczas instalowania istniejących projektów.

Daniel Tonon
źródło
5
Korzystam z wersji 5.4.2 i nadal powoduje to modyfikację mojego pliku package-lock.json, kiedy npm i. Na przykład moduł fseventsjest usuwany, gdy jestem npm ina komputerze, który nie obsługuje, fseventsa następnie moduł jest ponownie dodawany, gdy npm iponownie na komputerze, który obsługuje.
hrdwdmrbl
Następnie powinieneś poruszyć nowy problem wyjaśniający to w repozytorium npm GitHub. Jeśli to nie działa, jak mówią, że powinno działać, to widzą go jako błąd o wysokim priorytecie, który pilnie wymaga naprawy.
Daniel Tonon
@hrdwdmrbl widzę ten sam fseventsspadek w moim package-lock.jsonze [email protected]natomiast współpracuje z Mac OS X autorów. Jeśli nie otworzyłeś problemu, zrobię to.
AL, X
@hrdwdmrbl Znalazłem to (i długi wątek powiązanych problemów) po tym, jak zostawiłem swój komentarz i zapomniałem wrócić do SO, aby zaktualizować mój komentarz. Dzięki, że mnie odzyskałeś. Wszystko w porządku.
AL X X
4

Prawdopodobnie masz coś takiego:

"typescript":"~2.1.6"

w twoim, package.jsonktóre npm aktualizuje do najnowszej mniejszej wersji, w twoim przypadku2.4.1

Edycja: Pytanie od OP

Ale to nie wyjaśnia, dlaczego „instalacja npm” zmienia plik blokady. Czy plik blokady nie służy do tworzenia odtwarzalnej kompilacji? Jeśli tak, niezależnie od wartości semver, powinien nadal używać tej samej wersji 2.1.6.

Odpowiedź:

Ma to na celu zablokowanie pełnego drzewa zależności. Powiedzmy, że typescript v2.4.1wymaga widget ~v1.0.0. Po zainstalowaniu npm łapie widget v1.0.0. Później inny programista (lub kompilacja CI) wykonuje instalację npm i pobiera, typescript v2.4.1ale widgetzostała zaktualizowana do widget v1.0.1. Teraz moduł węzła nie jest zsynchronizowany. Co to jestpackage-lock.json zapobiega.

Lub bardziej ogólnie:

Jako przykład rozważ

pakiet A:

{„name”: „A”, „version”: „0.1.0”, „dependencies”: {„B”: „<0.1.0”}}

pakiet B:

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

i pakiet C:

{„name”: „C”, „version”: „0.0.1”}

Jeśli są to jedyne wersje A, B i C dostępne w rejestrze, wówczas zainstaluje się normalna instalacja A npm:

[email protected] - [email protected] - [email protected]

Jeśli jednak [email protected] zostanie opublikowany, wówczas zainstalowana zostanie nowa instalacja A npm:

[email protected] - [email protected] - [email protected], zakładając, że nowa wersja nie zmodyfikowała zależności B. Oczywiście nowa wersja B mogłaby obejmować nową wersję C i dowolną liczbę nowych zależności. Jeśli takie zmiany są niepożądane, autor A może określić zależność od [email protected]. Jeśli jednak autor A i autor B nie są tą samą osobą, autor A nie może powiedzieć, że nie chce pobierać nowo opublikowanych wersji C, gdy B w ogóle się nie zmienił.


Pytanie operacyjne nr 2: Pokażę, czy rozumiem poprawnie. Mówisz, że plik blokady określa wersje drugorzędnych zależności, ale nadal opiera się na rozmytym dopasowaniu pliku package.json w celu ustalenia zależności najwyższego poziomu. Czy to jest dokładne?

Odpowiedź: Nie. Pakiet-lock blokuje całe drzewo pakietów, w tym pakiety główne opisane w package.json. Jeśli typescriptjest zablokowane 2.4.1w twoim package-lock.json, powinno tak pozostać, dopóki nie zostanie zmienione. I powiedzmy, że jutro typescriptwypuszcza wersję 2.4.2. Jeśli sprawdzę twój oddział i uruchomię npm install, npm przestrzega pliku blokady i instaluje 2.4.1.

Więcej na package-lock.json:

Pakiet-lock.json jest generowany automatycznie dla wszystkich operacji, w których npm modyfikuje drzewo modułów_węzła lub pakiet.json. Opisuje dokładnie wygenerowane drzewo, dzięki czemu kolejne instalacje mogą generować identyczne drzewa, niezależnie od pośrednich aktualizacji zależności.

Ten plik ma być przeznaczony do repozytoriów źródłowych i służy do różnych celów:

Opisz pojedynczą reprezentację drzewa zależności, tak aby członkowie zespołu, wdrożenia i ciągła integracja gwarantowali zainstalowanie dokładnie tych samych zależności.

Zapewnij użytkownikom możliwość „podróży w czasie” do poprzednich stanów modułów_węzła bez konieczności zatwierdzania samego katalogu.

Aby ułatwić lepszą widoczność zmian drzewa dzięki czytelnym różnicom kontroli źródła.

I zoptymalizuj proces instalacji, pozwalając npm na pomijanie powtarzających się rozdzielczości metadanych dla wcześniej zainstalowanych pakietów.

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

Matt
źródło
29
Ale to nie wyjaśnia, dlaczego „instalacja npm” zmienia plik blokady. Czy plik blokady nie służy do tworzenia odtwarzalnej kompilacji? Jeśli tak, niezależnie od wartości semver, powinien nadal używać tej samej wersji 2.1.6.
Viper Bailey,
3
I o tym mówię. W moim pliku blokady pakietu jest napisany [email protected], ale kiedy uruchamiam npm install, wpis jest zastępowany [email protected].
Viper Bailey,
5
Wystąpił ten sam problem. W naszym CI / CD plik jest package-lock.jsonpobierany, a następnie uruchamiany npm install, ale package-lock.jsonplik jest modyfikowany i musimy wykonać reset, zanim będziemy mogli pobrać kolejne zmiany.
BayssMekanique
15
Nie rozumiem Co to za plik „blokady”, jeśli kolejne instalacje mogą nadal aktualizować ?!
Ross Allen
5
Myślę, że zaczęli od pomysłu, aby ten plik był „informacją” i „blokadą”, a następnie postanowili, że będzie to tylko plik „informacji”. Lepsza nazwa to „pakiet-info.json”. Chciałbym mieć „npm install -lock”, który zainstaluje się z „package-lock.json” i zignoruje „package.json”
Jeremy Chone
2

Prawdopodobnie powinieneś użyć czegoś takiego

npm ci

Zamiast używać, npm install jeśli nie chcesz zmieniać wersji swojego pakietu.

Zgodnie z oficjalną dokumentacją zarówno zainstalować , jak npm installi npm cizależności, które są potrzebne do projektu.

Główną różnicą jest to, npm installże instaluje pakiety, biorąc je packge.jsonza odniesienie. Tam, gdzie w przypadku npm ci, instaluje pakiety, biorąc je package-lock.jsonza odniesienie, upewniając się, że za każdym razem instalowany jest dokładny pakiet.

Sengottaian Karthik
źródło
1

Jest to otwarty problem na ich stronie github: https://github.com/npm/npm/issues/18712

Ten problem jest najpoważniejszy, gdy programiści używają różnych systemów operacyjnych.

hrdwdmrbl
źródło
Przepisane w lock-lock są zamierzone, problem nie jest konsekwencją tego
Z. Khullah
0

EDYCJA: nazwa „lock” jest trudna, jej NPM próbuje dogonić Yarn. To nie jest zablokowany plik. package.jsonjest plikiem ustalonym przez użytkownika, który po zainstalowaniu wygeneruje drzewo folderów node_modules, a następnie zostanie zapisane package-lock.json. Widzisz, jest na odwrót - wersje zależności będą pobierane package.jsonjak zawsze i package-lock.jsonpowinny być wywoływanepackage-tree.json

(mam nadzieję, że to wyjaśniło moją odpowiedź po tylu opiniach)


Uproszczona odpowiedź: zachowaj package.jsonswoje zależności jak zwykle, podczas gdy package-lock.jsonjest to „dokładne i, co ważniejsze, odtwarzalne drzewo modułów_węzła” (zaczerpnięte z samej dokumentacji npm ).

Co do podstępnej nazwy, jej NPM próbuje dogonić Yarn.

Z. Khullah
źródło
1
Ponieważ jeśli uruchomisz npm install, pakiet-lock zostanie zaktualizowany.
Jean-Baptiste