「依存関係」をそもそも論から掘り返すーpackage.jsonからnode_modulesについてー

## 前書き

### この記事の目的

技術的な調査をしているとき、解説文に出てきている用語の意味や、その文脈での意味合いが掴みきれずに、なんとなくで読み進めていくことってありませんか？

なんとなくで読み進めていくから、最後の方はほとんどが **”なんとなく”** の理解になっていて、どこまで行っても分かった **”つもり”** にしかなれないような、そんなあなた、そして、そんな私自身のための記事です。

できるだけ補足をつけていくので立ち止まりながらゆっくり読むような記事にできればと思います。

### 前提

この記事ではNode.jsを用いた開発を対象にしています。

（私はそれ以外にあまり触れたことがないので）

# 「依存関係」とは何を指すのか

そもそも論になりますが、

**「依存関係」**

この用語がなんとも初心者にはわかりにくいですよね。

まずは例を挙げます。

例えば、あなたが「ペンギン」というアプリを開発しているとします。

「ペンギン」はReact.jsを用いて開発しており、デザインはBootstrapというツールを使用しています。

React.jsを用いて開発しているわけですから、当然、「ペンギン」はReactが存在していないと正常に動いてくれません。

つまり、「ペンギン」はReactに **”依存している”** と言うことができます。

また、デザインはBootstrapがいい感じにしてくれるので、「ペンギン」はBootstrapにも **依存** しています。

その上で、BootstrapにはReactでの使用を前提としたツールセットのようなものも存在しているので、それを使用するとしたら、BootstrapもReactに依存していると言うことができるかもしれません。

イメージとしてはこんな感じ。

![依存関係.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2984157/33382cdd-8be2-b891-2408-b63e935f01d8.jpeg)


この一連の関係性のことを「依存関係」と言うのです。

# 「依存関係」は誰がどのように管理するのか

依存関係というものが何を指すのかが分かったところで、
「でもそれってどう管理しているの？」
という疑問に出会うかもしれません。

Node.jsでの開発では、`package.json`というファイルでそれを管理します。

## package.json

きっと皆さんが目にしたことのあるファイル名が出てきましたね。

「package.json　とは」でググると最初にこんな説明が出てきます。

> package.jsonは**Node.jsプロジェクトにおける依存関係管理やスクリプトの定義に必要なファイル**です。 外部パッケージの管理、バージョンの指定、プロジェクトの情報の記述など、プロジェクトの一貫性と管理を助ける重要な役割を果たします。
> 

引用元：https://gk-fe.com/article/about-packagejson/

今の段階では

- 外部パッケージの管理
- バージョンの指定

この二つができるファイルだと思ってもらえればいいです。

ここでいうパッケージというのが、前述の「ペンギン」におけるReactやBootstrapに該当します。

このファイルは、プロジェクトを作成する際にターミナルやコマンドプロンプトで

```jsx
npm init
```

などと入力すると勝手に作成されます。

Reactの雛形を作るときなんかは

```jsx
npx create-react-app my-react-app
```

みたいにしてもちゃんと作成されます。

せっかくなので、`npx create-react-app my-react-app` で作成したプロジェクトの`package.json`を確認してみましょう。

```jsx
{
  "name": "my-react-app",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@testing-library/jest-dom": "^5.17.0",
    "@testing-library/react": "^13.4.0",
    "@testing-library/user-event": "^13.5.0",
    "react": "^18.3.1",
    "react-dom": "^18.3.1",
    "react-scripts": "5.0.1",
    "web-vitals": "^2.1.4"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}
```

色々書いてありますが、今回重要なのはこの部分です。

```jsx
"dependencies": {
    "@testing-library/jest-dom": "^5.17.0",
    "@testing-library/react": "^13.4.0",
    "@testing-library/user-event": "^13.5.0",
    "react": "^18.3.1",
    "react-dom": "^18.3.1",
    "react-scripts": "5.0.1",
    "web-vitals": "^2.1.4"
  },
```

`dependencies`を和訳すると「依存関係」です。

つまり、これが依存関係を管理している部分です。

### dependencies

では、ここでどのようにして依存関係を管理しているのでしょうか？

それは先ほどの

- 外部パッケージの管理
- バージョンの指定

を決まった形式で記述して管理している、ということになります。

一例として

```jsx
"react": "^18.3.1",
```

を見てみましょう。

これは「Reactのバージョン18.3.1を使う」という指定です。

つまり、

```jsx
"外部パッケージ名": "バージョン",
```

ということになります。

つまり、依存関係を管理するということは、

「それぞれのパッケージのバージョンを適切に管理すること」

ということもできるかもしれません。

package.jsonとは、

「必要なパッケージの名前とバージョンのリスト」

だと思ってくれれば大丈夫です。

# パッケージをインストールする

では、そのリストをもとに実際にパッケージをインストールするのは誰なのでしょうか？

Node.jsにはその辺りをカバーしてくれる便利なシステム「npm」が備わっています。

<details><summary>補足：npmについて</summary>
    
本題からズレるので、npmについての説明は省きますが、詳しく知りたい方には下記の記事がおすすめです。
    
- [「そもそもnpmからわからない」](https://zenn.dev/antez/articles/a9d9d12178b7b2)
        
- [「NPMと言うのは？完全ガイド」](https://www.uxpin.com/studio/jp/blog-jp/npm%E3%81%A8%E3%81%AF%EF%BC%9F/)
</details>

使い方はとても簡単。

ターミナルやコマンドプロンプトで

```jsx
npm install
```

というコマンドを入力するだけです。

Node.jsさえ入っていれば正常にインストールが走ります。

## node_modules

`npm install`を実行すると、きっとあなたのプロジェクトには`package-lock.json`というファイルと`node_modules`というフォルダが生成されるはずです。

今回重要なのは`node_modules`なので、`package-lock.json`の細かい説明は省きます。

<details><summary>補足：package-lock.jsonについて</summary>
    
本題からズレるので、package-lock.jsonについての説明は省きますが、詳しく知りたい方には下記の記事がおすすめです。
    
- [「package.jsonとpackage-lock.jsonの違いについて」](https://qiita.com/phoby20/items/ca17d96bbf0da0b9989e)
        
- [「package-lock.json ってなに？」]( https://qiita.com/sugurutakahashi12345/items/1f6bb7a372b8263500e5)
</details>

`node_modules` とは `package.json` を元にしてインストールされる各種パッケージがインストールされるディレクトリ先のことです。

Node.jsがあなたの作成した`package.json`の依存関係リストをもとにして、実際のパッケージをネットワークを介して`node_modules`の中に格納します。

これだけでは曖昧な理解になる方もいるかもしれないので、例えてみます。

イメージとしては倉庫のようなものをイメージするといいかもしれないです。

![node_modules (1).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2984157/d89be9f8-1825-17de-4226-911e34e2ac51.jpeg)


Node.jsは注文（`npm install`）を受け付けると、発注リスト（`package.json`）をもとにインターネット上から商品（パッケージ）を探しに行って、倉庫（`node_modules`）に格納する、といった流れです。

あなたの開発プロジェクトでそれぞれのパッケージが必要になったときには、この`node_module`を参照します。

ここでよくある疑問としては、

「リストの管理なんかせずに、最初からパッケージを直接`node_modules`に格納しちゃえばいいじゃん」

という疑問だと思います。

その理由としては、

「後々面倒になるかもしれないから」

です。

先ほどの例のように２.３個しかパッケージがなければ実はそれほど面倒にはなりません。しかし、管理するパッケージが20個や30個になったら場合を想像すると、その面倒さと、リストと倉庫を分ける理由もわかります。

`package.json`でパッケージをリスト管理するとき、パッケージの名前とともにバージョン情報を管理していましたね。それはつまり、パッケージにおいてバージョンとは非常に重要な情報であることを指します。

バージョンが重要な情報ということは、

- バージョンが変わる可能性があるということ
- バージョンが変われば、パッケージの中身も変わること

が想像できます。

実際に、パッケージは適切に管理されていればいるほどアップデートが頻繁に発生します。

その内容は軽微な修正から、大幅な機能更新、重要なセキュリティ問題の解決など、多岐にわたります。

そういったものを確認し、毎回自分のプロジェクトのパッケージを手動で更新するのは非常に面倒であり、多分、ミスも発生します。

そのために、リストと倉庫というふうに分離させることで、管理を簡単にしています。

# 最後に

ここまで読めば、

- 依存関係
- package.json
- node_modules

などがそれぞれどんなものなのかがある程度わかったかと思います。

皆さんのプログラミングライフのささやかな手助けになれたら幸いです。

## ※

内容に指摘や補足がありましたら、適宜修正・補足の追加を行いますので、ぜひご指摘ください。

## 参考にした記事

- [「[npm]依存関係の解決に必要だった前提知識たち」](https://qiita.com/nktuk/items/5b9841290492bb12720d)
    
- [「npm installでのCould not resolve dependencyエラーと--legacy-peer-depsについて」](https://zenn.dev/minamiso/articles/78b22716f3338d)
    
- [【初心者向け】NPMとpackage.jsonを概念的に理解する](https://qiita.com/righteous/items/e5448cb2e7e11ab7d477)