まず結論
lockfile は、実際にインストールされたパッケージのバージョンを記録するファイルです。
package.json には、依存するパッケージとバージョンの条件が書かれます。一方、lockfileには「その条件を解決した結果、実際に何が入ったか」が記録されます。
代表的なlockfile:
package-lock.jsonpnpm-lock.yamlyarn.lockbun.lock
package managerによってファイル名が違います。
package.json だけでは足りない理由
package.json では、次のような書き方をよく見ます。
{
"dependencies": {
"astro": "^6.0.0"
}
}
^6.0.0 は、厳密に 6.0.0 だけを意味するわけではありません。条件に合う範囲で、より新しいバージョンが入る可能性があります。
自分のPCでは 6.1.0、別の人のPCでは 6.2.0 が入ると、同じコードなのに動きが変わることがあります。
lockfileは、この差を減らすために使います。
lockfile に書かれるもの
lockfileには、直接依存だけでなく、推移的依存も記録されます。
your-app
-> astro
-> vite
-> sharp
-> other packages
自分が直接入れたのは astro だけでも、Astroが必要とするパッケージがたくさんあります。lockfileは、その全体の解決結果を保存します。
CIで重要になる
CIや本番ビルドでは、毎回同じ依存関係で動かしたいです。
npmでは、CI向けに次のコマンドがよく使われます。
npm ci
npm ci は、lockfileをもとに依存関係をきれいにインストールします。package-lock.json と package.json がずれているとエラーになります。
これは不便ではなく、安全装置です。
lockfile はコミットするのか
アプリケーション開発では、基本的にlockfileをコミットします。
理由:
- チームで同じ依存関係にできる
- CIで同じ結果を再現しやすい
- 本番ビルドの差分を減らせる
- 依存関係更新の差分をレビューできる
ライブラリ開発では考え方が分かれることもありますが、WebサイトやWebアプリではコミットするのが一般的です。
lockfileが原因で起きること
よくあるトラブル:
package.jsonだけ変更してlockfileを更新していない- package managerを混在させて複数のlockfileがある
- lockfileの差分が大きすぎてレビューしにくい
- Node.jsのバージョン差で解決結果が変わる
複数のlockfileがあると、どれを正とするか分からなくなります。npmなら package-lock.json、pnpmなら pnpm-lock.yaml のように統一します。
注意: lockfileを雑に削除すると、依存関係が再解決されて別のバージョンが入ることがあります。削除は最後の手段として扱います。
まとめ
lockfileは、依存関係の解決結果を固定するための記録です。package.json が希望条件、lockfileが実際の解決結果だと考えると理解しやすくなります。
ビルドやCIの再現性を守るため、WebアプリやWebサイトではlockfileを大切に扱います。