package-lock.jsonについて知りたくても聞けなかったこと

# はじめに
`npm`でプロジェクトを始めると、目にする`package-lock.json`

![Screen Shot 2018-12-03 at 7.19.39.png](https://qiita-image-store.s3.amazonaws.com/0/252687/bbbabf77-e06f-d27c-014f-99300a9bccba.png)


今までこれ何だろう？:thinking:って思ってたけど、放置して進めていました。しかし、曖昧なままで置いておくのはダメだなと思い、一通りググって調べてみたところ、[Everything You Wanted To Know About package-lock.json But Were Too Afraid To Ask](https://medium.com/coinmonks/everything-you-wanted-to-know-about-package-lock-json-b81911aa8ab8)という記事がわかりやすかったので、こちらを翻訳してみました。

![Screen Shot 2018-12-03 at 14.18.52.png](https://qiita-image-store.s3.amazonaws.com/0/252687/3c5797ec-7c89-af00-29bb-b1bfd7281366.png)

以下内容です:point_down::point_down:

# 内容
## Introduction
`Node Package Manager(npm)`を`v5.x.x`にアップデートすると、全て問題ないように見えます。でもちょっと待って、何これ？`package-lock.json`という新しいファイルが自動生成されました。開いてみると、`package.json`の`dependencies`のように見えますが、より冗長です。ひとまず無視してプロジェクトを進めていくでしょう。そして依存性の問題に結果的にぶつかります。どこが悪いか見つからず、もしくは間違ったバージョンをインストールしてしまったのかもしれません。多くの人が`package-lock.json`を削除して`npm install`を実行することでしょう。それではなぜ、`package-lock.json`があるのでしょう？なんのためにあり、何を実際にするのでしょうか？

## Summary
- `npm ^5.x.x`を使っている場合、デフォルトで`package-lock.json`が生成されます
- 継続的インストールと依存関係を確実にするため`package lock`を使うべきです
- ソースバージョン管理に`package lock`を使いましょう
- `npm ^5.1.x`以降は`package.json`は`package-lock.json`を奥の手として持っており、悩ましさを軽減してくれます。
- `package-lock.json`を削除する必要はなく、`npm install`で再生成できる
- APIを提供している場合、セマンティックバージョン管理に従う

## Background
### Semantic Versioning 

`package-lock.json`や`package.json`を理解する前に、[セマンティックバージョン(sember)](https://semver.org/)について知る必要があります。これがとても優れており、`npm`の繁栄に導いたものでもあります。`npm`がどのようにこれを扱っているかは[こちら](https://blog.npmjs.org/post/162134793605/why-use-semver)の記事を参照ください。一言で言えば、他のアプリと連動するアプリを作っている場合、あなたが行う変更がどのような影響をもたらし、反映するかを明らかにしなければなりません。これが`セマンティックバージョン管理`で行われます。`X(メジャー), Y(マイナー), Z(パッチ)`という３つのバージョンパーツから成り立っております。例えば`1.2.3`というバージョンがあるとします。`1`がメジャーバージョンで、`2`がマイナーバージョン、`３`がパッチがとなります。パッチの変更は特に大きな影響を与えないバグ修正を、マイナーバージョンの変更も大きな影響はない機能的な変更を、メジャーバージョンの変更は互換性に影響を与える大きな変更を表します。ユーザーはメジャーバージョンの変更に対応しなければ、うまく動かなくなります。


### Managing Packages
`npm`はパッケージ管理を簡単にするために存在します。あなたのプロジェクトは何百もの`dependencies`(依存状態)を持っており、またそれぞれが何百という他の`dependencies`(依存先)にも依存しています。この`dependencies`地獄を回避するために、`npm`は存在しており、それらを特に考えなくてもいいよう、シンプルなコマンドでインストールから管理までを行うことができます。

パッケージを`npm`コマンドでインストールする際に、名前とバージョン番号を含めた項目が`package.json`に追加されます。(`npm`はセマンティックバージョンのワイルドカードを補います)。デフォルトで、`npm`は最新のバージョンをインストールし`^1.2.12`のような`キャレット(^:caret)`が付け加えられます。これは最低でもバージョン`1.2.12`が使われるべきであり、メジャーバージョンが同じである限り対応するということを示しています。マイナーバージョンやパッチ番号はバグ修正や大きな追加変更のみを表しているので、より最新のメジャーバージョンを使うことに問題はありません。セマンティックバージョン管理のワイルドカード、また使いやすいセマンティック計算については[こちら](https://medium.com/coinmonks/everything-you-wanted-to-know-about-package-lock-json-b81911aa8ab8)を参照ください

## Shared Projects
このような`dependencies`(依存関係)を明記している`package.json`を持つことのメリットは、その`package.json`にアクセスできる誰もがあなたのアプリケーションを使うために必要なモジュールを含む依存フォルダーを作成できることにあります。しかし、うまくいかない場合を見てみましょう

`express`(Node.jsのフレームワーク)を使う新規プロジェクトを作るとします。`npm init`をまず行い、`npm install express — save`で`express`をインストールします。この記事を書いている現時点では、`express`の最新バージョンは、`4.15.4`ですので、`"express": "^4.15.4"`と`package.json`の`dependencies`に追加され、コンピューターにも同じバージョンがインストールされます。そして翌日、`express`の管理をしている人がバグ修正を行いリリースした場合、最新バージョンは`4.15.5`になります。この時、もし誰かがこのプロジェクトに参加したく、クローンして`npm install`をするとします。すると同じメジャーバージョン内で`4.15.5`が最新となるので、それがその人のコンピューターにインストールされます。お互い`express`を持っていますが、違ったバージョンとなります。理論上は、互換性がありますが、おそらく先ほどのバグ修正が、使っている機能に影響し、`express@4.15.4`を起動させた場合に、`express@4.15.5`に比べ、違った結果をもたらすことがあります。<font color="red">(↑↑わかりやすい例)</color>

## Package-lock
### The Goal

`package-lock`の目的はこのような、同じ`package.json`からのモジュールインストールが、違ったインストールに陥る結果を回避するためにあります。`package-lock.json`は`npm version 5.x.x`で追加されました。ですので、もしメジャーバージョンが5以上であれば、無効化しない限り、`package-lock.json`が生成されるのを確認できます。<font color="red">(↑↑ここ大事)</color>


### The Format
`package lock`は`package.json`に記載されたそれぞれの依存先の大きなリストです。インストールされるべき厳密なバージョン番号、モジュールの場所(URI)、モジュールの統合性を確実にするハッシュ、必要とされるパッケージリスト、そして依存リストです。`express`の場合を見てみましょう


![Screen Shot 2018-12-03 at 15.32.31.png](https://qiita-image-store.s3.amazonaws.com/0/252687/35e347d2-3b72-ce05-6e73-2a053fb848c9.png)


対応する項目が`"requires"`セクションにある記載されたパッケージそれぞれにあります。

この考え方は`package.json`の代わりに、`package-lock.json`を使ってモジュールのインストールを行うことです。`package-lock`はバージョンを厳密に特定し統合ハッシュを全てのモジュールまたそれぞれの依存先に振り分け、インストール時に完全に同じ環境を構築するためです。どのようなデバイスを使おうと、将来的にどのタイミングでインストールしようとも、毎回同じ結果をもたらしてくれます。


### The Controversy
では、`package-lock`が一般的な問題を解決する場合、なぜググった際に(もしくは他の`npm`ドキュメントで)、`package-lock.json`を無効化もしくはその役割を疑問視するようなものが見つかるのでしょうか？

`npm 5.x.x`以前は、`package.json`はプロジェクトの信頼できる唯一の情報源でした。`package.json`に書かれていることが原則でした。`npm`ユーザーはこのモデルを好みパッケージファイルをこちらに適応させ管理してきました。しかし、`package-lock.json`は導入された際に、多くの人が期待していたものと正反対の動きをしました。すでに存在していた`package`と新しい`package lock`、多くの人が「信頼できる唯一の情報源」と考えていた`package.json`の変更は`package-lock.json`には反映されなかったのです。


**例：**`ver1.0.0`のパッケージAが、`package.json`と`package-lock.json`の両方にあるとします。`package.json`においてAが手動でver 1.1.0に編集されるとします。もし`package.json`を「信頼できる唯一の情報源」と考えるユーザーはここで、`npm install`を行うと、`ver 1.1.0`がインストールされることを期待します。しかしながら`package.json`には`v1.1.0`が記載されていますが、実際には`1.0.0`がインストールされます。


**例：** あるモジュールが`package.json`に存在し、`package-lock.json`にないとします。「信頼できる唯一の情報源」として、`package.json`を確認し、期待するモジュールがインストールされると考えます。しかし`package-lock.json`には明記されていないので、実際にはインストールされません。そしてモジュールが見つからないためエラーが起きます。


ほとんどの場合、彼らはなぜ自分の`dependencies`が正しくインストールされないか理解できないでしょう。よって、`package-lock.json`を削除するか再インストール、もしくは`package-lock.json`を無効化するでしょう。


この期待と現実の乖離問題は`npm`レポジトリスレッドに立った興味深い議論を引き起こしました。あるひとは`package.json`が「信頼できる唯一の情報源」としてみる一方で、ある人は、`package-lock`こそが`npm`がインストールする際に参照するものであると考えます。この議論の解決は`npm`の[PR #17508](https://github.com/npm/npm/pull/17508)にあります。NPMの管理者たちは`package.json`をアップデートしたら、`package-lock.json`を上書きするという変更を追加しました。よって今では両方の場合で、ユーザーが期待するパッケージが正確にインストールされるようになりました。この変更は`npm v5.1.0`でリリースされ、2017年7月5日(当時)でも有効です。


## 最後にまとめ
- 依存パッケージが依存するパッケージ(ネストした依存状態)のバージョン情報が変わる場合がある
- `package.json`だけでは、`node_modules`を完璧に再現できるとは限らない(勝手に違うバージョンのライブラリがインストールされてしまう可能性)
- `package-lock.json`はバージョン情報をすべて正確に記録する
- `package-lock.json` に書き込まれたバージョンのパッケージがインストールされる


## その他オススメ参考記事
- [npmのpackage.jsonと依存関係を理解しよう！](https://bagelee.com/programming/npm-package-json-dependencies/)
- [npm-package-lock-json-がなぜ必要なのかがわからない](https://ja.stackoverflow.com/questions/42788/npm-package-lock-json-%E3%81%8C%E3%81%AA%E3%81%9C%E5%BF%85%E8%A6%81%E3%81%AA%E3%81%AE%E3%81%8B%E3%81%8C%E3%82%8F%E3%81%8B%E3%82%89%E3%81%AA%E3%81%84)
- [package-lock.jsonの各プロパティについて調べてみました](https://qiita.com/shisama/items/bb816522a8468c3a367e)