初心者向けにJavaScriptのパッケージ管理の話など

## はじめに

- 各プログラミング言語にはたいていパッケージを管理するしくみがあります
    - RubyのgemだったりJavaのGradleやMavenだったり
- JavaScriptではnpmを使ってパッケージを管理します
- 新しいプログラミング言語をさわるときにパッケージ管理の仕組みを使いこなせることは、初心者から一歩踏み出せたと言っていいのではないかと思います
- この記事では初心者向けにnpm周りの使い方を紹介します

## 前提

- npmコマンドはnodeをインストールするとセットでついてきます
- なので事前にnodeをインストールしておいて下さい
- https://nodejs.org/ja/

## 依存パッケージの管理

- npmの仕組みでは依存するパッケージの情報を`package.json`で管理します
- 例えばちょうど手元にあったReactアプリの`package.json`は以下のようになっています

```json:package.json
{
  "name": "react-sample",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "react": "^16.8.2",
    "react-dom": "^16.8.2"
  },
  "devDependencies": {
    "eslint": "^5.13.0",
    "eslint-plugin-react": "^7.12.4"
  }
}
```

- `dependencies`と`devDependencies`に依存パッケージが記述されています
    - `dependencies`はアプリ本体に取り込まれる依存パッケージ
    - `devDependencies`は開発時のみに利用する依存パッケージ
- この`package.json`をカレントディレクトリにおいた状態で以下のコマンドを実行すると依存パッケージがインストールされます
    - `node_modules`ディレクトリが自動的に作成されそこにインストールされる

```bash
npm install
# もしくは
npm i
```

- このように`package.json`に依存パッケージを記述しておくことで、パッケージ本体をリポジトリ管理せずとも誰でも同じ状態を再現できるというわけですね

## 依存パッケージの追加

- 続いて新しく依存パッケージを追加するケースについてですが、直接`package.json`を編集する必要はありません
- 先程の`package.json`の状態で、新たに`react-router`というパッケージを使いたくなったとします
- その場合以下のコマンドを実行します

```bash
npm i react-router
```

- コマンドを実行すると`node_modules`にパッケージがインストールされ、さらに`package.json`の`dependencies`に自動で追記されます

```json:package.json
{
  "name": "react-sample",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "react": "^16.8.2",
    "react-dom": "^16.8.2",
    "react-router": "^5.0.0"
  },
  "devDependencies": {
    "eslint": "^5.13.0",
    "eslint-plugin-react": "^7.12.4"
  }
}
```

- さらに`eslint-plugin-react-hooks`というパッケージを追加したくなったとします
- このパッケージは開発時しか使わないため`devDependencies`に追加したいです
    - ESLint・・JavaScriptの構文チェックツール
- その場合以下のコマンドを実行します

```bash
npm i -D eslint-plugin-react-hooks
# もしくは
npm i --save-dev eslint-plugin-react-hooks
```

- 実行すると以下のように自動で追記されます

```json:package.json
{
  "name": "react-sample",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "react": "^16.8.2",
    "react-dom": "^16.8.2",
    "react-router": "^5.0.0"
  },
  "devDependencies": {
    "eslint": "^5.13.0",
    "eslint-plugin-react": "^7.12.4",
    "eslint-plugin-react-hooks": "^1.6.0"
  }
}
```

## ローカルインストールとグローバルインストール

- npmではパッケージのインストール先をローカルとグローバルを選択することができます
- これまで紹介してきたものは全てローカルにインストールしています
- グローバルにインストールする場合以下のようなコマンドを実行します

```bash
npm i -g create-react-app
# もしくは
npm i --global create-react-app
```

- パッケージはコマンドを実行したディレクトリではなくグローバルな場所にインストールされます
    - インストール先は`npm root -g`で確認できる
- グローバルインストールの使い所としては、アプリの雛形生成ツールなど開発中に何度も使わないようなものが向いているでしょう
    - 一度しか使わない => リポジトリで依存を管理する必要がない
- 先程インストールした`create-react-app`はReactアプリの雛形を生成するためのコマンドラインツールです
- 試しに以下のコマンドを実行するとReactアプリのベースが一式生成されます

```bash
create-react-app react-sample
```

- また、グローバルインストールと似た役割として`npx`というコマンドがあるので紹介しておきます
- 上記の手順だとグローバルにインストールしてコマンドを実行して、と面倒です
- さらに、グローバルにインストールしたパッケージのアップデートを怠っていると、意図せぬ古いパッケージを使ってしまうかもしれません
- `npx`を使うとその場でパッケージをインストールしコマンドを実行するということができます

```bash
npx create-react-app react-sample-2
```

- このコマンドは`create-react-app`をグローバルにインストールせずとも実行することができます
- 自分の場合最近はグローバルインストールを使う機会はあまりなく`npx`を使うことがほとんどです

## npm scripts

- パッケージ管理の話からは少しそれますが`npm scripts`についてふれておきます
- `npm scripts`とは`package.json`の中にscriptを定義しておき、それを実行できるというものです
- 先程登場した`create-react-app`で生成された雛形を例に見てみます
    - 雛形を生成していない方は`npx create-react-app react-sample`を実行して下さい

```json:package.json(一部抜粋)
{
  "name": "react-sample",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "react": "^16.8.6",
    "react-dom": "^16.8.6",
    "react-scripts": "2.1.8"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  }
}
```

- 雛形の中にある`package.json`を見ると`scripts`に4つの定義があります
- これらは`npm run start`や`npm run build`のようにして実行することができます
    - `npm start`と`npm test`だけは*run*を省略できます
- 試しに以下のようにlsコマンドの定義を追加してみましょう(実際こんなコマンドをセットすることはありませんが)

```json:package.json(一部抜粋)
{
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject",
    "lsa": "ls -a" 
  }
}
```

- 以下のコマンドを実行すると`ls -a`が実行されることが分かると思います

```bash
npm run lsa
> react-sample@0.1.0 lsa /Users/ozaki/Desktop/react-sample
> ls -a
.               .git            README.md       package.json    src
..              .gitignore      node_modules    public
```

- このようにして`npm scripts`を使うとnpmコマンドで任意のスクリプトを実行することができます
- ただ、これくらいなら直接実行しても変わらないのでは?と思うかもしれません
- 私は実際に開発していく中で以下のような恩恵を感じています
    - `npm start`で起動、`npm run build`でビルドといった共通認識があるため、他人のコードをさわる場合でも起動やビルドの方法がすぐに分かる
    - 定義するコマンドは状況によりオプションが追加されたり引数が増えたりすることがよくあるので`npm scripts`でラップされていることで意識しなくて良い
    - CIで実行する時も簡単なコマンドの設定でよくなり、オプションなどが変わっても実行するコマンドは変えなくて良い

## よくあるディレクトリ構成

- 最後にこれまたパッケージとは関係ありませんが、初心者がJavaScriptで作られたリポジトリを読む際の助けになればと思います
- ディレクトリ構造に慣れていないとgithubのページを開いて以下のようなファイルが並んでいると、どこを見ればいいのか分からないと感じることがあると思います

```
.
├── .env
├── .eslintrc.js
├── .git
├── .gitignore
├── .prettierrc
├── .storybook
├── .stylelintrc.js
├── README.md
├── build
├── jsconfig.json
├── node_modules
├── package.json
├── public
├── src
├── tsconfig.json
├── tsconfig.paths.json
└── yarn.lock
```

- トップレベルで並んでいる中で見るべきは`src`と`package.json`と`README.md`くらいと思って大丈夫です
    - `README.md`にリポジトリの説明を書いてくれている場合はまずはそこから読むとよいでしょう
    - `src`はコードの本体が入っているディレクトリなのでここがメインになります
    - `package.json`はこれまで紹介したように依存ライブラリなどの情報が書かれています
- さらに`src`の中を読むコツとして`index.js`というファイルを見つけたらまずそれを開くと良いです
    - `index.js`は暗黙的にエントリーポイント的な役割であることが多いのでそこからたどると読みやすいことが多いです

## npmとyarn

- 最後にと言いましたがもう一つ
- いろいろな記事やリポジトリを見ると`npm`的な立ち位置で`yarn`というものも目にするかと思います
- `yarn`は`npm`とほとんど同じなので慣れないうちは`yarn`と書いてあっても`npm`と置き換えて読むとよいです

## まとめ

- 今まで具体的なフレームワークやライブラリの記事をいくつも書いてきましたが、初心者にとってはnpm周りが実はとっつきにくいのかも？と思いいろいろと書いてみました
- これからJavaScriptを始めるエンジニアのお役に立てれば幸いです