Mengapa "npm install" menulis ulang package-lock.json?


614

Saya baru saja ditingkatkan ke npm @ 5 . Saya sekarang memiliki file package-lock.json dengan semuanya dari package.json . Saya berharap bahwa, ketika saya menjalankan npm installbahwa versi dependensi akan ditarik dari file kunci untuk menentukan apa yang harus diinstal di direktori node_modules saya . Apa yang aneh adalah bahwa itu akhirnya memodifikasi dan menulis ulang file package-lock.json saya .

Misalnya, file kunci memiliki naskah yang ditentukan untuk berada di versi 2.1.6 . Kemudian, setelah npm installperintah, versi diubah menjadi 2.4.1 . Itu tampaknya mengalahkan seluruh tujuan file kunci.

Apa yang saya lewatkan? Bagaimana saya mendapatkan npm untuk benar-benar menghargai file kunci saya?


4
Ini tidak menjawab pertanyaan Anda, jadi semoga komentar tidak apa-apa, tetapi lihatlah Benang. Perpindahan waktu kurang dari satu jam bagi kami.
KayakinKoder

4
Masalah yang sama tetapi menggunakan benang github.com/yarnpkg/yarn/issues/570 (sangat instruktif)
Yves M.

2
Saya memiliki masalah yang sama. Saya package-lock.jsonmendapatkan regenerasi ketika saya menjalankan npm install. Baunya seperti bug npm. Apakah Anda menggunakan registri Anda sendiri?
HaNdTriX


@YvesM. --no-savemencegah penguncian lockfile, tetapi itu tidak memengaruhi peningkatan ketergantungan tingkat pertama yang konyol yang disebutkan OP.
Ross Allen

Jawaban:


423

Pembaruan 3: Seperti jawaban lain tunjukkan juga, npm ciperintah diperkenalkan di npm 5.7.0 sebagai cara tambahan untuk mencapai build yang cepat dan dapat direproduksi dalam konteks CI. Lihat dokumentasi dan blog npm untuk informasi lebih lanjut.


Pembaruan 2: Masalah untuk memperbarui dan memperjelas dokumentasi adalah masalah GitHub # 18103 .


Pembaruan 1: Perilaku yang dijelaskan di bawah diperbaiki pada npm 5.4.2: perilaku yang dimaksud saat ini diuraikan dalam masalah GitHub # 17979 .


Jawaban asli: Perilaku package-lock.jsondiubah dalam npm 5.1.0 seperti yang dibahas dalam edisi # 16866 . Perilaku yang Anda amati tampaknya dimaksudkan oleh npm pada versi 5.1.0.

Itu berarti package.jsondapat menimpa package-lock.jsonkapan pun versi yang lebih baru ditemukan untuk dependensi di package.json. Jika Anda ingin menyematkan dependensi secara efektif, Anda sekarang harus menentukan versi tanpa awalan, misalnya, Anda harus menuliskannya sebagai 1.2.0ganti ~1.2.0atau ^1.2.0. Maka kombinasi dari package.jsondan package-lock.jsonakan menghasilkan membangun direproduksi. Agar lebih jelas: package-lock.jsonsendirian tidak lagi mengunci dependensi level root!

Apakah keputusan desain ini baik atau tidak dapat diperdebatkan, ada diskusi berkelanjutan yang dihasilkan dari kebingungan tentang GitHub ini dalam edisi # 17979 . (Di mata saya itu adalah keputusan yang dipertanyakan; setidaknya nama lockitu tidak berlaku lagi.)

Satu lagi catatan tambahan: ada juga batasan untuk pendaftar yang tidak mendukung paket yang tidak dapat diubah, seperti ketika Anda menarik paket langsung dari GitHub dan bukannya npmjs.org. Lihat dokumentasi kunci paket ini untuk penjelasan lebih lanjut.


43
Untuk apa retas npm updateitu? : o Saya memiliki perasaan yang sama dengan npm installupdate deps, tapi saya tidak ingin mempercayainya .. tapi sepertinya itu benar sekali .. Lagi pula masih ada opsi untuk digunakan npm shrinkwrapuntuk mengunci deps, tapi pasti nama paket-kunci salah karena tidak membeku, atau mengunci dependensi ..
Jurosh

266
Berantakan sekali! Pengelola paket terbesar di dunia namun tidak memiliki dokumentasi tentang cara kerjanya. Semua orang menebak tentang apa yang harus dilakukan dan itu berubah menjadi perang pendapat. Diskusi itu baik tetapi harus terjadi sebelum rilis ke alam liar. Pada titik tertentu seseorang perlu membuat panggilan terakhir dan kemudian dapat diimplementasikan, didokumentasikan dan dirilis. PHP dirancang oleh komite dan ad-hoc'd bersama-sama dan lihat bagaimana hasilnya. Aku benci melihat hal yang sama terjadi pada alat yang kritis dan banyak digunakan ini.
Landon Poch

85
Lalu, apa gunanya menggunakan kunci-paket? Saya pikir itu akan menciptakan lingkungan yang sama di ruang kerja yang berbeda tetapi ternyata tidak melakukan apa
laltin

17
"Lalu kombinasi package.json dan package-lock.json akan menghasilkan build yang dapat direproduksi." Peran apa yang dimiliki "package-lock.json" di sini? Bukankah "package.json" saja sudah menghasilkan build yang dapat direproduksi jika tidak ada awalan versi yang digunakan?
Jānis Elmeris

12
@ JānisElmeris Saya pikir package.json tidak dapat mengunci dependensi yang dalam ...
Juan Mendes

165

Saya telah menemukan bahwa akan ada versi baru npm 5.7.1 dengan perintah baru npm ci, yang akan menginstal dari package-lock.jsonsaja

Perintah npm ci baru HANYA instal dari file kunci Anda. Jika package.json Anda dan file kunci Anda tidak sinkron maka itu akan melaporkan kesalahan.

Ia bekerja dengan membuang node_modules Anda dan membuatnya kembali dari awal.

Selain menjamin Anda bahwa Anda hanya akan mendapatkan apa yang ada di file kunci Anda, itu juga jauh lebih cepat (2x-10x!) Daripada menginstal npm ketika Anda tidak memulai dengan node_modules.

Seperti yang Anda ambil dari namanya, kami berharap ini menjadi keuntungan besar bagi lingkungan integrasi berkelanjutan. Kami juga berharap bahwa orang-orang yang melakukan penyebaran produksi dari git tag akan melihat keuntungan besar.


133
Ini harus menjadi perilaku default jika ada lockfile.
nullability

13
Jadi mereka mengubah cara npm saya bekerja, hanya untuk mengembalikannya sebagai npm ci bulan kemudian?
Scott Flack

1
Saya masih bingung. Dokumentasi mengatakan "Pastikan Anda memiliki kunci paket dan instal terbaru: npm install" sebelum menjalankan perintah npm cidalam proyek itu. Tidak npm installmenimpa file package-lock.json?
Adiga

1
AFAIK: @adiga - dimulai dengan versi 5.4, npm hanya mengubah file kunci jika perlu untuk melakukannya, untuk memenuhi spesifikasi dalam paket.json . Jadi jika paket digunakan untuk mengatakan thatpackage: 1, dan mengunci mengatakan ..: 1.0.4, dev dapat mengedit untuk mengatakan thatpackage: 2- dan itu akan memaksa file kunci untuk berubah, karena 1.0.4tidak kompatibel dengan kisaran yang baru ditentukan. Jika tidak berubah packages.json, akan tetap terkunci pada versi yang tepat, hingga menghapus file kunci. [Jika tidak tetap terkunci, dan tidak mengubah
paket.json

1
@ George Dari informasi yang saya baca (untuk versi terbaru dari npm), dan pengujian terbatas saya: ya untuk keduanya.
Venryx

95

Gunakan yang baru diperkenalkan

npm ci

npm ci menjanjikan manfaat terbesar bagi tim besar. Memberi pengembang kemampuan untuk "keluar" pada kunci paket mempromosikan kolaborasi yang lebih efisien di seluruh tim besar, dan kemampuan untuk menginstal apa yang ada di lockfile berpotensi menyelamatkan puluhan bahkan ratusan jam pengembang dalam sebulan, membebaskan tim untuk menghabiskan lebih banyak waktu membangun dan mengirimkan hal-hal menakjubkan

Memperkenalkan npm ciuntuk pembuatan yang lebih cepat dan lebih andal


3
ini tampaknya benar bagi saya? adakah yang bisa mengkonfirmasi?
phouse512

6
@ phouse512 Ini benar. Kami cukup banyak hanya menggunakan npm ci, dan hanya menggunakan npm installjika memperbarui atau menginstal paket baru.
Jacob Sievers

1
Komentar terbaru, dll. Ini adalah jawaban yang saya terima. Sayang sekali mereka tidak bisa memperbaiki snafu yang mengerikan, tetapi jika Injil baru adalah "npm ci", maka baiklah. Saya bisa beradaptasi.
Svend

Sayang sekali selalu menghapus node_modulesdirektori yang ada dan membangun kembali secara lokal, bahkan jika itu adalah symlink kosong tetapi penting. :(
Joe Atzberger

2
@ToolmakerSteve Jangan menahan nafasmu! Saya pikir menghapus isi direktori akan jauh lebih lambat daripada hanya menghapus direktori. Anda harus menghitung konten kemudian mengeluarkan serangkaian perintah hapus daripada hanya satu perintah hapus ke O / S. Dengan masalah kinerja yang sebelumnya diratakan pada npm dan peningkatan penggunaan, npm cisaya berharap mereka akan sangat enggan untuk memperkenalkan apa pun yang dapat mengurangi kinerja untuk kasus penggunaan yang tidak biasa. Anda mungkin ingin memeriksa pnpm.js.org meskipun itu menggunakan tautan keras untuk mengurangi penggunaan disk.
Caltor

64

Jawaban singkat:

  • npm install menghormati package-lock.json hanya jika memenuhi persyaratan package.json.
  • Jika tidak memenuhi persyaratan tersebut, paket diperbarui & kunci-paket ditimpa.
  • Jika Anda lebih baik gagal membangun, daripada menulis ulang kunci-paket saat itu terjadi, gunakan npm ci.

Berikut adalah skenario yang mungkin menjelaskan hal-hal (Diverifikasi dengan NPM 6.3.0)

Anda mendeklarasikan dependensi dalam package.json seperti:

"depA": "^1.0.0"

Kemudian Anda lakukan, npm installyang akan menghasilkan package-lock.json dengan:

"depA": "1.0.0"

Beberapa hari kemudian, versi minor "depA" yang lebih baru dirilis, katakan "1.1.0", kemudian yang berikut ini berlaku:

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)

Selanjutnya, Anda memperbarui paket Anda secara manual ke:

"depA": "^1.1.0"

Kemudian jalankan kembali:

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
Ini memang perilaku yang dimaksudkan dari file "kunci". Rupanya, itu tidak terjadi dengan versi NPM yang lebih lama.
Blockost

1
Lalu bagaimana npm melacak pembaruan terakhir ke package.json? Apa yang terjadi ketika Anda memindahkan package.json dan package-lock.json ke komputer lain? Bagaimana npm di komputer baru mengetahui apakah package.lock adalah yang asli atau telah diperbarui, untuk memutuskan apakah perlu memperbarui package-lock.json atau tidak?
Lahiru Chandima

3
@LahiruChandima Tidak benar-benar melacak pembaruan. npm installakan menggunakan versi terkunci dari package-lock.jsonkecuali itu tidak memenuhi package.jsondalam hal itu menginstal package.json dan membangun kembali package-lock.json sesuai. Jika Anda mengubah Anda package.jsonsedemikian rupa sehingga kunci-paket yang ada masih memenuhi pembaruan package.jsonitu akan terus menggunakannyapackage-lock
Ahmad Abdelghany

1
Jika Anda sudah memiliki modul di node_modules yang memenuhi persyaratan package.json, maka npm installtidak melakukan apa pun, terlepas dari package-lock.json. Kami harus memperbarui paket secara eksplisit bahkan ketika ada pembaruan yang tersedia yang cocok dengan semver yang ditentukan dalam package.json. Setidaknya itu sudah pengalaman saya selama bertahun-tahun.
carlin.scott

1
@ToolmakerSteve Saya juga skeptis dengan perilaku @ carlin.scott yang dilaporkan, tetapi saya baru saja mengujinya, dan ternyata dia benar. Jika versi dalam node_modulesmemenuhi kisaran di package.json, dan tidak ada package-lock.jsonfile, npm tidak akan memperbarui modul saat berjalan npm install. Saya kira itu baik-baik saja karena Anda dapat menggunakan npm update(atau npm-checkuntuk yang terbaru) untuk memperbarui dependensi, dan perilaku ini lebih cepat untuk kasus seseorang hanya menambahkan satu entri package.json, dan tidak ingin paket yang tidak terkait memperbarui diri ke yang terbaru yang memenuhi sem-ver jarak.
Venryx

19

Gunakan npm ciperintah sebagai ganti npm install.

"ci" adalah singkatan dari "continuous continuous".

Ini akan menginstal dependensi proyek berdasarkan pada file package-lock.json alih-alih dependensi file package.json yang ringan.

Ini akan menghasilkan build identik dengan rekan tim Anda dan juga jauh lebih cepat.

Anda dapat membaca lebih lanjut tentang hal ini di posting blog ini: https://blog.npmjs.org/post/171556855892/introducing-npm-ci-for-faster-more-r reliable


2
cimerujuk pada "integrasi berkelanjutan", sebagaimana disebutkan dalam dokumen dan posting blog yang mengumumkan perintah: blog.npmjs.org/post/171556855892/...
Joe Atzberger

Joe terima kasih Saya telah memperbarui jawaban saya dengan nama yang benar dan tertaut ke posting blog. 😊 (bagi mereka yang membaca ini, sebelumnya saya mengatakan bahwa itu adalah singkatan dari "clean install")
Daniel Tonon

"Dan itu juga jauh lebih cepat" - itu akan menghapus node_modulesfolder dan membuatnya kembali dari awal. Apakah ini jauh lebih cepat? Apakah npm installmenghapus node_modulesfolder juga?
izogfif

Saya pikir kecepatannya berasal dari npm tidak perlu menghitung paket apa yang harus diunduh. Anggap saja seperti npm installharus menyelesaikan semua dependensi paket ketika dijalankan. npm cihanyalah daftar belanjaan "dapatkan modul ini dengan tepat"
Daniel Tonon

8

Di masa depan, Anda akan dapat menggunakan --from-lock-filebendera (atau serupa) untuk menginstal hanya dari package-lock.jsontanpa mengubahnya.

Ini akan berguna untuk CI, dll. Lingkungan di mana bangunan yang direproduksi penting.

Lihat https://github.com/npm/npm/issues/18286 untuk melacak fitur tersebut.


Aku meragukan itu. Bagaimana jika dependensi berbeda untuk sistem operasi yang berbeda, bagaimana Anda bisa memaksa memasang sesuatu yang tidak akan berfungsi?
Yevgeniy Afanasyev

4
@YevgeniyAfanasyev Alih-alih bendera itu, itu diimplementasikan sebagai npm ciyang juga menangani pertanyaan Anda.
spex

8

Tampaknya masalah ini diperbaiki di npm v5.4.2

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

(Gulir ke bawah ke komentar terakhir di utas)

Memperbarui

Sebenarnya diperbaiki dalam 5.6.0. Ada bug lintas platform di 5.4.2 yang menyebabkan masalah masih terjadi.

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

Perbarui 2

Lihat jawaban saya di sini: https://stackoverflow.com/a/53680257/1611058

npm ci adalah perintah yang harus Anda gunakan saat menginstal proyek yang ada sekarang.


5
Saya menggunakan 5.4.2 dan masih menghasilkan modifikasi paket-lock.json saya kapan npm i. Sebagai contoh, modul fseventsdihapus ketika saya npm ipada mesin yang tidak mendukung fseventsdan kemudian modul ditambahkan kembali ketika satu npm ilagi pada mesin yang tidak.
hrdwdmrbl

Maka Anda harus mengangkat masalah baru di repo GitHub npm yang menjelaskan ini. Jika tidak berfungsi bagaimana mereka mengatakan itu seharusnya bekerja maka mereka melihatnya sebagai bug prioritas tinggi yang sangat perlu diperbaiki.
Daniel Tonon

@hrdwdmrbl Saya melihat fseventspenurunan yang sama package-lock.jsondengan saya npm@5.5saat berkolaborasi dengan kontributor Mac OS X. Jika Anda belum membuka masalah, saya akan melakukannya.
AL the X

@hrdwdmrbl Saya menemukan itu (dan utas panjang terkait masalah) setelah saya meninggalkan komentar saya dan lupa untuk kembali ke SO untuk memperbarui komentar saya. Terima kasih telah mendapatkan punggungku. Semuanya baik-baik saja.
AL the X

4

Anda mungkin memiliki sesuatu seperti:

"typescript":"~2.1.6"

di package.jsonmana npm Anda memperbarui ke versi minor terbaru, dalam kasus Anda2.4.1

Sunting: Pertanyaan dari OP

Tetapi itu tidak menjelaskan mengapa "npm install" akan mengubah file kunci. Bukankah file kunci dimaksudkan untuk membuat bangunan yang dapat direproduksi? Jika demikian, terlepas dari nilai semver, masih harus menggunakan versi 2.1.6 yang sama.

Menjawab:

Ini dimaksudkan untuk mengunci pohon ketergantungan penuh Anda. Katakanlah typescript v2.4.1membutuhkan widget ~v1.0.0. Ketika Anda npm instal ambil widget v1.0.0. Kemudian rekan pengembang Anda (atau CI build) melakukan instalasi npm dan mendapatkan typescript v2.4.1tetapi widgettelah diperbarui widget v1.0.1. Sekarang modul simpul Anda tidak sinkron. Inilah yang package-lock.jsonmencegah.

Atau lebih umum:

Sebagai contoh, pertimbangkan

paket A:

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

paket B:

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

dan paket C:

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

Jika ini adalah satu-satunya versi A, B, dan C yang tersedia di registri, maka instal normal npm A akan menginstal:

A@0.1.0 - B@0.0.1 - C@0.0.1

Namun, jika B@0.0.2 diterbitkan, maka instal baru npm A akan menginstal:

A@0.1.0 - B@0.0.2 - C@0.0.1 dengan asumsi versi baru tidak mengubah dependensi B. Tentu saja, versi B yang baru dapat mencakup versi C baru dan sejumlah dependensi baru. Jika perubahan tersebut tidak diinginkan, penulis A dapat menentukan ketergantungan pada B@0.0.1. Namun, jika penulis A dan penulis B bukan orang yang sama, tidak ada cara bagi penulis A untuk mengatakan bahwa ia tidak ingin menarik versi C yang baru diterbitkan ketika B tidak berubah sama sekali.


OP Pertanyaan 2: Jadi biarkan saya melihat apakah saya mengerti dengan benar. Apa yang Anda katakan adalah bahwa file kunci menentukan versi dependensi sekunder, tetapi masih bergantung pada pencocokan fuzzy package.json untuk menentukan dependensi tingkat atas. Apakah itu akurat?

Jawab: Tidak. Kunci-paket mengunci seluruh paket pohon, termasuk paket-paket root yang dijelaskan di package.json. Jika typescriptdikunci di 2.4.1dalam Anda package-lock.json, itu harus tetap seperti itu sampai diubah. Dan katakanlah besok typescriptrilis versi 2.4.2. Jika saya checkout cabang Anda dan menjalankan npm install, npm akan menghormati lockfile dan menginstal 2.4.1.

Lebih lanjut tentang package-lock.json:

package-lock.json secara otomatis dihasilkan untuk operasi apa pun di mana npm memodifikasi pohon node_modules, atau package.json. Ini menjelaskan pohon persis yang dihasilkan, sehingga instalasi berikutnya dapat menghasilkan pohon yang identik, terlepas dari pembaruan ketergantungan menengah.

File ini dimaksudkan untuk dijadikan repositori sumber, dan melayani berbagai tujuan:

Jelaskan representasi tunggal dari pohon dependensi sehingga rekan tim, penyebaran, dan integrasi berkelanjutan dijamin untuk menginstal dependensi yang persis sama.

Menyediakan fasilitas bagi pengguna untuk "melakukan perjalanan waktu" ke keadaan sebelumnya dari node_modules tanpa harus melakukan direktori itu sendiri.

Untuk memfasilitasi visibilitas perubahan pohon yang lebih besar melalui perbedaan kontrol sumber yang dapat dibaca.

Dan optimalkan proses instalasi dengan memungkinkan npm untuk melewati resolusi metadata berulang untuk paket yang sebelumnya diinstal.

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


29
Tetapi itu tidak menjelaskan mengapa "npm install" akan mengubah file kunci. Bukankah file kunci dimaksudkan untuk membuat bangunan yang dapat direproduksi? Jika demikian, terlepas dari nilai semver, masih harus menggunakan versi 2.1.6 yang sama.
Viper Bailey

3
Dan itulah yang saya katakan. File kunci paket saya mengatakan typescript@2.1.6 tetapi ketika saya menjalankan instalasi npm, entri tersebut diganti dengan typescript@2.4.1.
Viper Bailey

5
Saya pernah mengalami masalah yang sama. Dalam CI / CD kami, yang package-lock.jsonditarik ke bawah dan kemudian kami jalankan npm install, tetapi package-lock.jsonfile tersebut dimodifikasi dan kami harus melakukan reset sebelum kami dapat menarik perubahan berikutnya.
BayssMekanique

15
Saya tidak mengerti. Bagaimana ini file "kunci" jika instalasi selanjutnya mungkin masih melakukan upgrade ?!
Ross Allen

5
Saya pikir mereka mulai dengan gagasan memiliki file ini sebagai "info" dan "kunci" dan kemudian, memutuskan itu hanya akan menjadi file "info". Nama yang lebih baik adalah "package-info.json". Saya ingin memiliki "npm install -lock" yang akan menginstal dari "package-lock.json" dan abaikan "package.json"
Jeremy Chone

2

Mungkin Anda harus menggunakan sesuatu seperti ini

npm ci

Alih-alih menggunakan npm install jika Anda tidak ingin mengubah versi paket Anda.

Menurut dokumentasi resmi, keduanya npm installdan npm cimenginstal dependensi yang diperlukan untuk proyek.

Perbedaan utama adalah, npm installapakah menginstal paket mengambil packge.jsonsebagai referensi. Di mana dalam kasus npm ci, itu menginstal paket mengambil package-lock.jsonsebagai referensi, memastikan setiap kali paket yang tepat diinstal.



0

EDIT: nama "kunci" adalah yang rumit, NPM-nya berusaha mengejar ketinggalan dengan Benang. Ini bukan file yang terkunci. package.jsonadalah file yang diperbaiki pengguna, yang pernah "diinstal" akan menghasilkan pohon folder node_modules dan kemudian pohon itu akan ditulis package-lock.json. Jadi Anda lihat, ini sebaliknya - versi ketergantungan akan ditarik package.jsonseperti biasa, dan package-lock.jsonharus dipanggilpackage-tree.json

(Semoga ini membuat jawaban saya lebih jelas, setelah banyak downvotes)


Sebuah jawaban sederhana: package.jsonmemiliki dependensi Anda seperti biasa, sementara package-lock.json"pohon node_modules tepat, dan lebih penting direproduksi" (diambil dari npm docs sendiri ).

Adapun nama yang rumit, NPM-nya berusaha mengejar ketinggalan dengan Benang.


1
Karena jika Anda menjalankan instalasi npm, kunci-paket akan diperbarui.
Jean-Baptiste
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.