【その他】npmについて理解しよう

#はじめに
JavaScriptを使って開発や勉強をしていると、**npm** や **package.json** という用語をよく目にします。
しかし、何となく書いてある通りのコマンドを実行していましたので、詳しく調べてみました。

#npmとは
npmとは**Node Package Manager**の略で、JavaScriptライブラリのパッケージマネージャーです。

その名の通りNode.jsで動くライブラリが主ですが、現在ではブラウザで動くJavaScriptライブラリや
コマンドラインツールなど様々なパッケージが登録されています。

npmプロジェクトの情報管理しているのが **package.json** というファイルです。このファイルを手動で編集したり
 **npm コマンド**を通して更新していきます。
**npm コマンド**はNode.jsをインストールすると一緒にインストールされます。

##npm initコマンドを使う
npm init コマンドを使って pakage.json を作成します。

```
$ npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.

See `npm help json` for definitive documentation on these fields
and exactly what they do.

Use `npm install <pkg>` afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
package name: <プロジェクトのパッケージ名>
version: <バージョンコード(x.y.z形式)>
description: <パッケージの説明>
entry point: <ライブラリとして呼び出されるときのエントリーポイント>
test command: <テストコマンド>
git repository:  <gitリポジトリのURL>
keywords: <関連ワード>
author: <作者名>
license: <ライセンス(MIT, GPLなど)>
```

いろいろと情報を入力する必要がありますが、これらの情報はプロジェクトをnpmパッケージとして公開するときに使われます。
公開する予定がない場合は省略したり適当に入力してしまっても構いません。

##package.jsonがすでに存在しているとき
最近のWebフレームワークはJavaScript関連の機能をnpmに任せてしまっていることが多く、
その場合はプロジェクトを作成すると最初から package.json が入っています。

この場合は既に入っているライブラリを消すと正しく動かないので、 入っている package.json に追記する形で、
必要に応じてpackageやversionなどを書き換えて使います。


#package.json の中身
世の中のパッケージのpackage.jsonは例えば以下のようになっている。
.jsonという拡張子からもわかるように、このファイルは JSON と呼ばれる形式に従っている。


```json:package.json
{
  "name": "my-package",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lint": "vue-cli-service lint",
    "deploy": "vue-cli-service build && firebase deploy --project=prod"
  },
  "dependencies": {
    "@innologica/vue-dropdown-menu": "^0.1.4",
    "core-js": "^3.6.5",
    "firebase": "^8.3.1",
    "vue": "^2.6.11",
    "vue-click-outside": "^1.1.0",
    "vue-nl2br": "^0.1.2",
    "vue-router": "^3.2.0",
    "vuex": "^3.4.0"
  },
  "devDependencies": {
    "@vue/cli-plugin-babel": "~4.5.0",
    "@vue/cli-plugin-eslint": "~4.5.0",
    "@vue/cli-plugin-router": "~4.5.0",
    "@vue/cli-plugin-vuex": "~4.5.0",
    "@vue/cli-service": "~4.5.0",
    "axios": "^0.21.1",
    "babel-eslint": "^10.1.0",
    "eslint": "^6.7.2",
    "eslint-plugin-vue": "^6.2.2",
    "sass": "^1.26.5",
    "sass-loader": "^8.0.2",
    "vue-template-compiler": "^2.6.11"
  }
}
```

開発を進める際に、

- npm init 
- npm install
- npm run 

上記のコマンドをよく使うかとおもいます。



```json:package.json
 "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lint": "vue-cli-service lint",
    "deploy": "vue-cli-service build && firebase deploy --project=prod"
  },
```

**npm run 【serve】**や**npm run 【build】**、npm run 【deploy】はよく使うのですが、

**scripts**に入っている、 **serve**、**build**、**lint**、**deploy**が【】内にあたります。
その後ろにある**"vue-cli-service serve"**,**"vue-cli-service serve"**,**"vue-cli-service build && firebase deploy --project=prod"**が
動きの指示する部分になります。

```json:package.json
"scripts": {
    "deploy": "vue-cli-service build && firebase deploy --project=prod"
  },
```

こちらがわかりやすいかと思いますが、**npm run deploy** とコマンドを入力すると
**vue-cli-service build** &&(かつ) **firebase deploy --project=prod**を実行するように指示しています。

このようによく使うもコマンドは自分で内容を書き換えて効率化に繋げることも大事であると思います。

##dependenciesについて

例えば、 vue-dropdown-menu というライブラリを追加するために

```
$ npm install vue-dropdown-menu
```

というコマンドを実行すると、 vue-dropdown-menu がインストールされた上で、 package.json に以下のように書き込まれます。

```json:package.json
  "dependencies": {
   "@innologica/vue-dropdown-menu": "^0.1.4",
  }
```

右の数字はバージョン番号で、 npm install を実行したときの最新のリリースバージョンが書き込まれます。
dependenciesに追加されたパッケージは、次からは単に

```
$ npm instal
```

のみでインストールされます。


##devDependenciesについて
また、 --save-dev というオプションを使って依存関係を追加することもできます。

```
$ npm install --save-dev eslint
```

このコマンドを実行すると、 eslint がインストールされ、 pakage.json には以下のように書き込まれます。

```
  "devDependencies": {
    "eslint": "^6.7.2",
  }
```

--save-dev を使うと、dependenciesではなくdevDependenciesとして追加されます。

この2つには以下の違いがあります。

npm install に --production が渡されたり環境変数が NODE_ENV=production にセットされているとき、
devDependenciesはインストールされない

そのプロジェクトがnpmパッケージとしてインストールされたとき、dependenciesのパッケージは一緒にインストールされるが、
devDependenciesはインストールされない


##POINT
全てdependenciesに追加してしまってもいいのですが、これらの違いはNode.jsサーバーとして動かすときやパッケージを公開するときに影響してきます。
普段から、プログラムの動作には必要なく開発やテストのときのみに使うパッケージはdevDependenciesとして追加するように意識するといいでしょう。

#バージョン番号とロックファイルを理解
##バージョン番号と記号
先ほど、バージョン番号として ^6.7.2 のような数字がでてきましたが、先頭についている ^ は何なのでしょう。
^ は省略することができたり、他にも ~ という記号をつけることがよくあります。

このようにバージョン番号を3つの数字で表すとき、それぞれを x.y.z とすると、


**x: メジャーバージョン**
**y: マイナーバージョン**
**z: パッチバージョン**

と呼びます。このバージョン番号に ^ や ~ を付けた場合以下のような意味になります。

 4.17.10: 完全一致 (version = 4.17.10)
^4.17.10: メジャーバージョンが一致 (4.17.10 <= version < 5.0.0)
~4.17.10: マイナーバージョンが一致 (4.17.10 <= version < 4.18.0)
これは、ライブラリに機能改善やバグ修正があった場合に自動で適用してくれるための仕組みです。

##ロックファイルとは
この仕組みによって勝手に違うバージョンのライブラリがインストールされてしまうと、
プロジェクトを何もいじっていないのにライブラリのバージョンが変わって急に動かなくなった、ということが起こると困りますよね。
（一般にはメジャーバージョンが変わらない限り後方互換性を持たせるルールですが、守られない場合もあります）

そこで登場するのがロックファイルです。
npm install を実行すると package-lock.json というファイルが作成されるのですが、これがロックファイルです。
**package.json に変更がない限りは package-lock.json に書き込まれたバージョンのパッケージがインストールされます。**
こういった理由があるため、gitを使っていてロックファイルをgitignoreするべきかどうかという質問がよくあるのですが、
git管理下に追加するようにしましょう。

#npmとyarn
この記事では npm コマンドを使っていましたが、npmパッケージのインストールには yarn というコマンドを使うこともできます。
**yarn は npm コマンドのインストール速度などを改良することを目指して開発されたツール**で、同じnpmのパッケージを参照しますし、 package.json によって管理するところも同じです。

依存関係に追加されたnpmパッケージをインストールする際、
package-lock.json の代わりに yarn を使うと yarn.lock というロックファイルが作成されます。

複数人で開発する場合や既存のプロジェクトを引き継ぐ場合、どちらのロックファイルが存在するかを見て
npm を使うか yarn を使うかを統一するといいでしょう。

他の記事でご紹介している create-react-app や react-native init で作るReact(Native)のプロジェクトは、
yarn がインストールされている場合そちらを優先して使うようになっています。