package.jsonとpackage-lock.jsonのバージョン指定や必要性について

# はじめに
業務内でpackage.jsonやpackage-lock.jsonを使う機会があり、学んだことをまとめる。

# Node.jsとnpm
メインの話ではないので細かい説明は省略。

・Node.js
Node.jsは、「JavaScriptの実行環境」。Node.jsを使うことで、サーバー側でJavaScriptを使うことが出来るようになる。

・npm
npmは、Node Package Manuagerの略でNode.jsのパッケージ管理ツール。


詳しい説明はこちらを→[Node.jsとはなにか？なぜみんな使っているのか？](https://qiita.com/non_cal/items/a8fee0b7ad96e67713eb)

npmはNode.jsをインストールする際に一緒にインストールされる。


# package.jsonとpackage-lock.jsonについて


## Semantic Version
Semantic Versionとは、バージョン番号を付けるにあたり決めたルールのこと。

細かい仕様については、下記サイトでまとまっている。
[セマンティック バージョニング 2.0.0](https://semver.org/lang/ja/)

Node.jsでは、このSemantic Versioning(semver)に従ってバージョン表記をしている。
semverでは、以下のように`X.Y.Z`のように３つの数字で表される。

- X：major version　後方互換性のない変更
- Y：minor version　後方互換性のある変更
- Z：patch version　後方互換性のあるバグ修正など

メジャーバージョンが上がると、マイナーバージョンとパッチバージョンの値は0となる。
マイナーバージョンが上がると、パッチバージョンの値は0となる。

メジャーバージョンは後方互換性がない変更であるため、その点注意する必要がある。


例）

```json
"devDependencies": {
        "bootstrap": "^4.0.0"
}
```

この例の場合は、bootstrapパッケージでメジャーバージョンが4、マイナーバージョンと、パッチバージョンが0という風に対応している。

ただ、注意する点として先頭についている^(キャレット)がある場合は、あるルールにのっとってその範囲内のバージョンへのアップデートを許容する。

## ^(キャレット)
上記の例でもあったようにバージョン指定する際に、`"bootstrap": "^4.0.0"`のように記載してあることがある。この先頭についているものが^(キャレット)である。

キャレットについて、npm Docsに以下のような説明があります。

> Caret Ranges ^1.2.3 ^0.2.5 ^0.0.4
Allows changes that do not modify the left-most non-zero digit in the [major, minor, patch] tuple. 
引用元：[semver](https://docs.npmjs.com/cli/v6/using-npm/semver)

翻訳すると、

> [major, minor, patch]タプルの左端のゼロ以外の数字を変更しない変更を許可します 。

どういうことか実際にいくつかの例をもとに説明する。

`^1.2.3`の場合
一番左端のゼロ以外の数字はメジャーバージョンを示す`1`。そのため、メジャーバージョンを変更しないようなアップデートを許容する。
ここでのバージョンアップ許容範囲は、 `1.2.3 <= N < 2.0.0`となる。

`0.2.3`の場合
一番左端のゼロ以外の数字はマイナーバージョンを示す`2`。そのためメジャーバージョンとマイナーバージョンを変更しないようなアップデートを許容する。
ここでのバージョンアップ許容範囲は、`0.2.3 <= N < 0.3.0`となる。

`0.0.3`の場合
一番左端のゼロ以外の数字はパッチバージョンを示す`3`。そのため、ここでのバージョンアップ許容範囲は、`0.0.3 <= N < 0.0.4`となる。


## ~(チルダ)
キャレットの他にもバージョン範囲指定がいくつかありその中に~(チルダ)がある。

npm Docsに以下のような説明があります。

> Tilde Ranges ~1.2.3 ~1.2 ~1
Allows patch-level changes if a minor version is specified on the comparator. Allows minor-level changes if not.

翻訳すると、

> コンパレータでマイナーバージョンが指定されている場合、パッチレベルの変更を許可します。そうでない場合は、マイナーレベルの変更を許可します。

どういうことか実際にいくつかの例をもとに説明する。

`~1.2.3`の場合
この場合は、マイナーバージョン部分の`2`が指定されているため、パッチレベルのアップデートを許容する。バージョンアップ許容範囲は、`1.2.3 <= N < 1.3.0`となる。

`~1.2`の場合
この場合は、マイナーバージョン部分の`2`が指定されているため、パッチレベルのアップデートを許容する。バージョンアップ許容範囲は、`1.2.3 <= N < 1.3.0`となる。

`~1`の場合
この場合は、マイナーバージョンが指定されていないため、マイナーバージョンのアップデートを許容する。バージョンアップ許容範囲は、`1.0.0 <= N < 2.0.0`となる。


### 参考

- [package.jsonのパッケージバージョンに記載される ^ (キャレット) とは？どうしてつくのか？](https://dackdive.hateblo.jp/entry/2016/10/04/095200)
- [セマンティック バージョニング 2.0.0](https://semver.org/lang/ja/)
- [Semantic Versioning おさらい](https://dev.classmethod.jp/articles/summary-for-semver/)
- [semver(npm Docs)](https://docs.npmjs.com/cli/v6/using-npm/semver)


## package-lock.jsonの必要性
今回学習初期段階のイメージとしては、package.jsonに記述してあるバージョンを入れて、入れたバージョン情報などがpackage-lock.jsonに自動的に記述されるだけという感じだった（不十分）。

しかし、先ほどのSemantic Versionでも触れたようにpackage.jsonでは入れるバージョンをある程度の範囲で指定することができる。そのため、実際にパッケージをインストールするタイミングによってはパッケージのバージョンが異なってしまうという問題がある。

チーム内で同じ環境を構築したい場合、バージョンが異なってしまうと困る。
このインストールするバージョンを固定するために必要なのが、`package-lock.json`である。


`npm install`を実行する際、package-lock.jsonがない場合はpackage.jsonに従ってパッケージがインストールされますが、package-lock.jsonがある場合は基本的には***package-lock.jsonのバージョンで固定してインストールすることが出来る***。

これを自分は知らなかったため、最初インストールしたバージョンが他の環境と異なってしまうという問題に遭遇した。

これらのことから、どちらのファイルも非常に重要であるためもしGit管理する場合はどちらもコミットする必要がある。

また、npm installの具体的な挙動として以下のようになっているとのこと。

> npm v6.9.0 時点ではnpm installの具体的な挙動は次のようになっている。
・`package-lock.jsonが存在しないとき`
`package.json`に基づいて dependency がインストールされ、実際にインストールされたバージョンが`package-lock.json`に書かれる。
・`package-lock.json`が存在するとき
`package-lock.json`に基づいてインストールされるが、`package.json`指定されたバージョンとの矛盾があれば、`package.json`が優先され、実際にインストールされたバージョンが`package-lock.json`に書かれる。
引用元：[【初心者向け】NPMとpackage.jsonを概念的に理解する](https://qiita.com/righteous/items/e5448cb2e7e11ab7d477#package-lockjson)

package.jsonとpackage-lock.jsonの指定バージョンに矛盾があった場合は、package.jsonが優先されるとのことなのでこの点注意したい。


### 参考
[package.jsonとpackage-lock.jsonの運用方法について](https://engineering.mobalab.net/2019/08/08/package-json%E3%81%A8package-lock-json%E3%81%AE%E9%81%8B%E7%94%A8%E6%96%B9%E6%B3%95%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6/)


# まとめ
今回は、package.jsonとpackage-lock.jsonのバージョン指定や必要性について簡単にまとめた。
まだまだ、理解が不十分であるため引き続き理解を深めていきたいと思います。