パッケージ・マネージャ (Webアプリ開発基本シリーズ　2)

Webアプリ開発基本シリーズ

※ 下記の人が対象のシリーズとなっています。

- Webアプリ開発をこれから学ぶ人
- なんとなくで開発していたので、基礎からしっかり学びたい人
- Alt JS や WebPack などを使った モダンなWebアプリ開発 を学びたい人

1. [Webアプリ開発基本](https://qiita.com/EBIHARA_kenji/items/2727c03335ddaea9c520)
1. **パッケージマネージャ** <-いまここ
1. [JavaScript でよく使用されるライブラリ](https://qiita.com/EBIHARA_kenji/items/8fb2ca35ae2e1b8859b7)
1. ECMAScript と TypeScript
1. Webpack
1. Webフレームワーク
    1. React
    1. Vue.js

## 概要

Webアプリケーションに限らず、システム開発では多くのOSS（だけではないですが）ライブラリを利用することが多いです。

以前は、ブラウザでWebサイトからソースやバイナリのファイルをダウンロードしてプロジェクト内にコピーしていました。

しかし、この方法では下記の問題があります。

- Gitなどの構成管理には、OSSライブラリを履歴管理する必要はないが、入れない場合各開発者がダウンロードする必要がある。その場合バージョンを合わせることやライブラリの数が増えると単純作業でも手間が大変になる。
- ライブラリが依存している他のライブラリがある場合、関係性を把握して入れないといけない。
- 脆弱性の修正等のバージョンアップを利用しているライブラリのサイトを巡回して確認しないといけない。
- 開発環境で利用するツール類も同様で、特にプロジェクトごとに使用するバージョンが異なる場合などは困難となる。

このような問題を解決するため、システム開発ではパッケージマネージャを利用するのが、ほぼ必須です。

## npm

JavaScriptの開発では、パッケージマネージャとして npm を使います。

npm は node.js の公式のパッケージマネージャで、node.js とセットでインストールされます。（Windows の場合）

https://nodejs.org/ja/

node.js をインストールして、実際に試してみましょう。

プロジェクトのソースフォルダを見立てた、空のフォルダを用意してください。コンソールでここを開いてください。

npm では、ルートに package.json という設定のためのファイルが必要です。ここには、プロジェクトの名前やバージョン、ライセンス情報、使用するライブラリなどの情報を記載します。

これは、npm init のコマンドで作成することができます。コンソールで実行しましょう。

いくつか質問されますが、とりあえず全て Enter キーを押していきましょう。

package.json ファイルができたと思います。これを開くと、先程質問された内容を JSON で書かれています。

続けて React をインストールしてみます。コンソールで、`npm install react` を実行します。

package.json に、dependencies が追加され、そこに react とバージョンの表示があります。

フォルダには、node_modules が作成され、その中に react と他のフォルダが見えます。

先程のコマンドで、React とそれに関連するライブラリがダウンロードされ、node_modules に展開されました。

では、node_modules をフォルダごと削除して、`npm install` を実行してみてください。

再び node_modules が作成され、そのなかに先程と同じ react と他のフォルダが見えます。

node_modules にはこのように npm でインストールされたライブラリなどのパッケージが入ります。`npm install xxxx` で package.json にインストールしたパッケージが記載され、`npm install` で、package.json の中を参照しここにあるパッケージをダウンロードしてくれます。

よって、Git には、このフォルダは対象外として入れないようにし、他の開発者は `npm install` するだけで、同じライブラリを用意することができます。

他にも、パッケージをバージョンアップ・削除したり、依存関係を調べたり、脆弱性の報告されているバージョンのものを使用していないかチェックするなどのコマンドがあります。

どのようなパッケージがあるかは、`npm search` コマンドでも良いですが、公式サイトで検索することをおすすめします。ここでは、Readme のドキュメント、更新頻度、利用者数などが確認でき、パッケージの採用の判断に必要な情報があります。

https://www.npmjs.com/

開発環境で使用する、ESLint や TypeScript などのツールも npm で入れます。その場合は、`npm install -D eslint` とします。実行してみましょう。

package.json に devDependencies が追加され、そこに eslint が書かれています。これは、実行環境に必要なものではなく、開発環境のみで必要なもの、と区別するためのものです。

## yarn

yarn は、非公式のパッケージマネージャで、npm が不便なところとより使いやすくする目的で作られたものです。npm と互換性があります。package.json もそのまま使えるので、単純にコマンドを置き換えることが可能です。(コマンド名は異なります)

```
yarn add react
yarn add -D eslint
# すべてのパッケージをインストールする
yarn (install) # install は不要
```

ただ、npm のバージョンアップに伴い、その弱点がなくなってきているので、yarn の利点は薄くなっていますが、多くのプロジェクトで使われており、OSSの公式のドキュメントでも yarn で説明しているところも多いです。

個人的には、ほんの少しの利便性の差で yarn の方を好みます。ただ、npm で動いているプロジェクトを無理に yarn に変更するほどのものではないですね。

## npm / yarn next...

現在の npm の仕組みでは、パッケージのインストールに時間がかかったりや node_modules のサイズが肥大化するなどの課題があります。

これらを解決するために、yarn の新しいメジャーバージョンでは PnP （プラグ・アンド・プレイ） という独自機能を導入します。これは、完全に yarn 独自の機能で、npm と互換性がありません。

とても有用な仕組みなのですが、ライブラリやツールの多くがまだ対応しきれず、個人的には yarn 1 からの移行も難しいと感じました。

npm も tink という同じ問題を解決する仕組みを計画しています。

しかし、現状でもその問題が致命的になることもないので、今後 yarn pnp / tink が受け入れられ、多くのライブラリが対応するまで待ってもいいかな、と思っています。

- [npm, yarn による zero install 戦略 - from scratch](https://yosuke-furukawa.hatenablog.com/entry/2019/06/10/113111)
- [npm/tink: a dependency unwinder for javascript](https://github.com/npm/tink)
- [Plug'n'Play | Yarn - Package Manager](https://yarnpkg.com/features/pnp)


## パッケージの利用

npm や yarn でインストールしたライブラリを使うにはどうしたら良いのか、ということですが、webアプリではパッケージマネージャを利用します。

node.js では、そのまま試すことができるので、ここで実践してみましょう。

日付を扱うライブラリである、dayjs をインストールします。

```
npm install dayjs
```

インストールできたら、`index.js` を作成し、下記コードを書いてください。

```js
const dayjs = require("dayjs");

const date = dayjs().startOf("hour");

console.log(date);
```

実行してみましょう。

```
node ./index.js
```

JSON のようなものが表示されましたが、date オブジェクトの内容になります。

dayjs() は、現在の時刻の Dayjs オブジェクトを返します。

startOf は、日や時間のはじめの値を取得するもので、この場合は、現在時刻の0時0分0秒 を返します。ちなみに、endOf もあります。

別な記法として、import も使えます。node.js で実行する場合、package.json に `"type": "module"` を足します。

```json
{
  "name": "practice01",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "dependencies": {
    "dayjs": "^1.10.6"
  },
  "type": "module"
}
```

```js
import dayjs from "dayjs";

const date = dayjs().startOf("hour");

console.log(date);
```

こちらのほうが、ECMAScript の定義されている使い方で、TypeScript でも この書き方をすることが多いですので、import 形式になれておくと良いでしょう。

webブラウザでは、require も import もそのままでは対応していないので、webpack などのモジュールバンドラを使用します。

webpack に関しては、別のセクションで説明します。

## ツール類のパッケージ

コマンドラインから実行できるパッケージもあります。

例えば、webpack や Typescript などもコマンドラインから実行できるライブラリです。

ここでは、sloc というソースコードの行数をカウントするライブラリを導入してみます。

多くの場合このようなツールは、開発環境で使うものなので、`-D` をつけておきます。

```
npm install -D sloc
```

node_modules フォルダを見ると、`.bin` というフォルダがあります。ここに、sloc の実行ファイルがあります。

これを実行するために、わざわざここに移動する必要はありません。npx というコマンドで実行できます。

```
npx sloc index.js
```

結果が表示されました。このように、コマンドラインのツールも入れてすぐに実行することが出来ます。

yarn の場合は、yarn のあとにコマンド名を入れるだけで実行できます。

```
yarn sloc index.js
```

## npm スクリプト

npm では簡易なタスクランナーの機能があります。ここに、独自のコマンド名とそのシェルコマンドを定義できます。

`npm init`したときに、scripts に test というのがありますが、これになります。

`npm test` を実行すると、ここに書かれたシェルコマンドが実行されます。

TypeScript を コンパイルするときなど、対象フォルダを空にして、TypeScript のコマンドを実行するなど、一連のコマンドをいちいち打つのが面倒です。そのようなときに、それをここに定義して、簡単に間違いなく実行できるようにしておくと、効率が上がります。

また、ある npm script の前に別の npm script を実行するなどの連携もできます。

https://ics.media/entry/12226/

https://www.twilio.com/blog/npm-scripts-jp

yarn でも `yarn test` のように実行できます。

npm もで、yarn でも、それぞれで用意されているコマンド（install, add など）と重複しないようにします。重複する場合は、`yarn run install` とすることで実行することはできますが、煩雑なだけなのでできるだけ避けましょう。

## まとめ

Webに限らず、システム/アプリケーション開発では、パッケージマネージャを利用するのが当たり前になっています。

プラットフォームや言語によって使うツールは様々ですので、必要に応じてそれぞれの基本的な使い方を把握しておきましょう。