3秒でわかる
npm が実際に入れた依存パッケージの版と取得元を記録するファイル。同じ環境を全員の手元と本番で再現するために存在します。
もう少し詳しく
どういうものか
package-lock.json は、npm install を実行した結果として決まった依存関係の完全な状態を記録するファイルです。直接指定したパッケージだけでなく、その依存が必要とするパッケージまで含め、どの版をどこから取得し、内容のハッシュが何であるかが書かれています。
package.json が「どの範囲なら許すか」を書いた希望であるのに対し、package-lock.json は「実際に何が入ったか」という結果です。npm install を実行すると自動で作られ、更新されます。
なぜ必要か
package.json では依存の版を ^18.2.0 のように範囲で書きます。この記法は 18.2.0 以上 19.0.0 未満を許すため、install する日が違えば入る版も違います。自分の手元では 18.2.0、CI では 18.3.1 という状態が起こり、動かない理由が環境差なのかコードなのか切り分けられなくなります。
lock ファイルがあれば、その中身どおりの版が入ります。数か月前のコミットに戻したときも、当時と同じ依存で再現できます。ハッシュが記録されているため、取得したファイルが差し替えられていないことの確認にも使われます。
具体例
{
"name": "my-app",
"lockfileVersion": 3,
"packages": {
"node_modules/react": {
"version": "18.2.0",
"resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
"integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==",
"engines": { "node": ">=0.10.0" }
}
}
}CI やデプロイでは install ではなく ci を使います。
npm cinpm ci は package-lock.json だけを見て node_modules を作り直します。lock と package.json が食い違っていればエラーで止まるため、意図しない版が混入しません。install より速いのも、依存解決を省けるためです。
つまずきやすいところ
「自動生成されるファイルだから」と .gitignore に入れてしまう例があります。アプリケーションでは逆で、必ずコミットします。無視してよいのは、利用側の環境に合わせる必要があるライブラリを公開する場合です。
競合が出たときに手で編集するのも避けます。構造が壊れると原因の分からない不具合につながるため、package.json 側の競合だけ解消してから lock を作り直します。
git checkout --theirs package-lock.json
npm install複数人が別々の npm メジャー版を使っていると lockfileVersion が行き来し、毎回巨大な差分が出ます。Node と npm の版はプロジェクトでそろえます。
似た用語との違い
| ファイル | 役割 |
|---|---|
| package.json | 許容する版の範囲と設定を書く |
| package-lock.json | 実際に入った版を固定する |
| node_modules | 展開された実体。コミットしない |
覚え方
package.json は注文票、package-lock.json は納品書。次に同じものが欲しければ、見るのは納品書のほうです。