npmとnpxの違いって何？ yarnとかpnpmとかって?[Node]

# はじめに
JavaScriptでライブラリをインストールしたいと思った時に、`npm`コマンドを使おうと思ったのですが、ライブラリの公式ドキュメントをみると`npx`コマンドを使っているケースをよく見かけます。

<font color="red">npxってなんだ？npmと何が違うの？

ってなったので調べてみようと思います。


# 前提知識

## Node.js
そもそも`Node.js`って知らない間に使用しているケースが多いですよね。

`Node.js`はパソコン上で、JavaScriptのプログラムを実行するためのJavaScriptの実行環境です。

元々、JavaScriptはブラウザ上のみで動作することを想定して作られた言語で、ブラウザ上でしかJavaScriptのプログラムを実行することができませんでした。

これはどういうことかというと、PythonやGoといったような言語はパソコン上で使用することが可能で、OSの機能にアクセスしてファイル操作等が可能でした。
JavaScritptは、ブラウザ上で動作する言語のため、ブラウザ(Webアプリケーション)からOSの操作を行うというのはセキュリティ上問題があるので、パソコン上で動かせなかったということです。
>OSの操作の全てができないだけで、カメラ等の限定的な機能は使えます


## パッケージ
`package.json`で管理しているプロジェクトを言います。
パッケージという名前ですが、概念的には`ライブラリ`や`フレームワーク`と同じです。

## packcage.json
プロジェクトで使用するパッケージの依存関係を記述しています。
ここに記述されたものを`npm install`でインストールしたりします。

## package-lock.json
インストールされたパッケージを記述しています。

:::note
package.jsonは、インストールすべきパッケージを記述
package-lock.jsonは、結果的にインストールされたパッケージを記述しています。
:::

## node_modules
`npm install`コマンドを使ってインストールされたパッケージが集められるディレクトリのことです。

# じゃあnpmとnpxって何？

前提知識を入れたところで、npmとnpxの違いについて説明しようと思います。

## npm(Node Package Manager)
Node.jsを入れると自動的にインストールされるパッケージマネージャーのことを指します。

npmを使うことで依存関係や競合関係を解決してくれます。

:::note
#### 依存関係
依存関係は、パッケージを動かすのにまた別のパッケージが必要なことを言います。
例えば、`パッケージa`を入れた時に`パッケージb`を入れるのが必要となった場合に、パッケージマネージャーが`a`を入れたら`b`も自動的に入れてくれることです。
:::

:::note
#### 競合関係
競合関係は、依存関係が同じパッケージがあった時に、同じパッケージを2度も入れてしまうことを言います。
例えば、`パッケージa`と`パッケージc`で、依存関係として`パッケージb`があった時に、それぞれのパッケージを入れた際に複数回`パッケージb`を入れることになってしまい、ディスクスペースの無駄になってしまいます。
:::


## npx(Node Package Executor)
npxはパッケージの実行ツールです。
インストールされていないパッケージを探してインストールして、インストールを完了したらそのパッケージを削除してくれます。

例えば、npmではインストールされたパッケージやpackge.jsonに記述されたパッケージを動かす際に
```:zsh
npm run
```
を行うのですが、その内部で動いているツールです。

### なぜインストールにnpxを使っているところがあったりするのか
先述したようにnpxは一時的にインストールして、使い終わったら削除します。

例えば、Next.jsのプロジェクトで`shad/cn`等のUIコンポーネントライブラリを使いたいとしましょう。
shad/cnのパッケージはコンポーネントを記述するようになっているので
```:zsh
npx shadcn@latest add button
```
とコマンドを打った場合、これはbuttonコンポーネントの追加パッケージを実行しています。

この追加パッケージは一度しか使う必要がないので、npxを使ってパッケージを実行したら削除しています。

仮にnpmを使用した場合は、一度しか入れる必要がないbuttonコンポーネントを入れるようのパッケージを`node_modules`に対して、ずっと入れることになってしまい、容量を圧迫してしまいます。

一度しか使う必要がないパッケージは、npxを使ってパッケージを実行したら削除することで、環境を汚さずに使用するというメリットがあります。

なので、ReactやNextのプロジェクトを立ち上げるときも立ち上げる時に使用するパッケージは一度実行するだけなので
```:zsh
npx create-react-app my-app
```
```:zsh
npx create-next-app@latest
```
って打ちますよね。

また、npxで一時的にパッケージをインストールすることから、最新バージョンのパッケージを使えるという利点があります。

:::note
#### npxの利点
- 容量を圧迫する必要がない
- 最新バージョンを持って来ることができる
:::

## npmとnpxでのインストールの違い

上記を踏まえてnpmとnpxの使い方の違いとしては

- npm: プロジェクトを動かすために入れるパッケージをインストールするとき
- npx: 一度実行したらいらなくなるパッケージを使いたいとき

となります。

このようにケース毎にnpmとnpxを使い分けています。

# yarnとpnpmについて

npmとまた違うパッケージマネージャーとしてyarnとpnpmがあります。

自分もインターン等でyarnとpnpmを使ったことがありますが、違いがわからないませんでした。

今回npmを調べるということでついでに調べてみました。

## yarn
Facebookが作成したパッケージマネージャーです。

npmと互換性があるので、同じ`PackageManager`を使ってインストールすることができます。

yarnは、ダウンロードされたパッケージはキャッシュするので、インストール速度が早いという特徴があります。


数年前まではyarnのほうがnpmよりパッケージのインストール速度が早かったらしく、それで人気が出たそうです。
>現在はnpmもそこまで速度に差が無いと言われているので、もはや好みなのかなと思っています。

Yarn はコード実行前に、インストールされた各パッケージの整合性をチェックサムで検証するので、セキュリティ面で高いという特徴もあります。

:::note
yarnの特徴
- インストールが若干npmより早い
- セキュリティ面が高い
:::

## pnpm
Performant NPMの略称で、こちらもnpmやyarnと同じパッケージマネージャーです。

ただこちらはnpmと比べると違いがいろいろあります。

### 1.ストレージの効率
npmやyarnは、プロジェクト毎にパッケージをインストールしていたため、複数のプロジェクトにそれぞれ同じパッケージが入っているということが起きていました。

pnpmでは、そのパッケージを一箇所に集め、それに対するリンクを使用することでストレージを節約しています。

### 2.インストールが高速
JavaScriptのパッケージマネージャーでは、インストールする際に、`Resolving`、`Fetching`、`Linking`を行っていました。

それぞれ
- `Resolving`:依存関係の解決
- `Fetching`:ディレクトリ構造の計算
- `Linking`:依存関係をリンク
を行っています。

従来は、以下の画像のように、複数パッケージをインストールするとなったら。全てのパッケージがResolving->Fetching、Fetching->Linkingと段階移行を確定させていないと実行できませんでした。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3766230/425d0886-3087-1efe-a444-d75a763d4b32.png)
>引用元:https://pnpm.io/ja/next/motivation

pnpmでは、下画像のようにそれぞれのパッケージが各ステージを進めるようになったことで、インストールが高速化しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3766230/5cbcab4c-5cb9-cbff-ea2e-86a04e14799d.png)
>引用元:https://pnpm.io/ja/next/motivation


### 3.packcage.jsonが厳格化
npm等では、一つのパッケージを動かすために必要なパッケージをインストールしていました。
pnpmでは、先述したようにリンクを使用してパッケージを使用します。
そのリンクひとつだけをpackage.jsonを記述することで、動かすためだけに必要なパッケージをpackage.jsonに記述する必要がなくなり、必要なパッケージのリンクだけをpackage.jsonに書くようになっています。
これで意図しないパッケージの動作を制限できます。

:::note
pnpmの利点
- パッケージがディスクを圧迫しない
- インストールが早い
- 依存関係が厳格
:::


# 最後に

ライブラリ毎にnpmやnpx異なると思いますが、npmとnpxの特性を理解しておくとそのライブラリについての知識が深まっていいと思います。

また、nodeのパッケージマネージャーはどれもいいものなので、周りの経験値や要件に合わせて使用したらいいと感じました。

>個人的にはpnpmいいなと思っています