yarn (+ webpack) を使ってみる

どっちもよく知らないですが、よく見かけるので使ってみようと思いました。

## Yarn (jɑːn - [やよ]ーん) とは何か？

https://github.com/yarnpkg/yarn

* JSのパッケージマネージャ。
   * `npm` のbetterな代替品という感じか。
   * Rubyでいう、 `bundler` みたいなものです。
      * プロジェクトローカルなコマンドインストールも兼ねていて、 `bundle exec ~~~` が `yarn run ~~~` に相当するみたいな感じ。
   * 依存性管理以外は基本やらないので、パッケージングとかは `webpack` とか使ってください。
* 並列DL、依存性の正確で再現可能な記録と計算、パッケージの破損チェックがサポートされている。

## Webpack とは何か？

https://webpack.github.io/

* なんかWeb系のプロジェクトのモジュールを1ファイルに固めてくれたりするビルドツール。（Cでいうリンカみたいな）
   * よくある、依存しているライブラリと、自プロジェクトの複数のJSを1ファイルにまとめる、みたいな用途で特に大した設定もせず使えるので、便利だと思われます。
      * 1ファイルではなく、論理的なグルーピングにくっつけるといったのも可能。
   * JS以外も扱えるらしい。
* `npm install -g webpack` でインストールできますが、今回はYarn経由でプロジェクト内にインストールします。

## Yarnのインストール

### macOS

```
brew install yarn
```

### Windows

```
choco install yarn
```

### Linux

パッケージのDL元を追加してインストールせよとのこと。

https://yarnpkg.com/en/docs/install#linux-tab

### npm （非推奨）

npm経由でも入れられるようですが、非推奨とのこと。

https://yarnpkg.com/en/docs/install#alternatives-tab

> Note: Installation via npm is generally not recommended. npm is non-determinstic, packages are not signed, and npm does not perform any integrity checks other than a basic SHA1 hash, which is a security risk when installing system-wide apps.
> 
> For these reasons, it is highly recommended that you install Yarn through the installation method best suited to your operating system.

要するにnpmのパッケージ解決が気まぐれ、しかもパッケージが破損・改変されていても気づけ無いから、おすすめしませんとのことらしいですが、何を今更という気はします。

気にしない人はnpmで入れちゃいましょう。

```
npm install -g yarn
```


## 適当なプロジェクトを開始してみる

(cf. https://yarnpkg.com/en/docs/usage)

`test-yarn` というプロジェクト名ではじめてみます。

```console
$ mkdir test-yarn
$ cd !$
$ yarn init
yarn init v0.17.10
question name (test-yarn):
question version (1.0.0):
question description:
question entry point (index.js):
question git repository:
question author:
question license (MIT):
success Saved package.json
✨  Done in 8.48s.
```

中身は `package.json` だけが作られます。

```json:package.json
{
  "name": "test-yarn",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT"
}
```

ちょうどjQueryしたい気分なので、jQueryへの依存性を追加してみましょう。


```
$ yarn add jQuery
yarn add v0.17.10
info No lockfile found.
[1/4] 🔍  Resolving packages...
[2/4] 🚚  Fetching packages...
[3/4] 🔗  Linking dependencies...
[4/4] 📃  Building fresh packages...
success Saved lockfile.
success Saved 1 new dependency.
└─ jquery@3.1.1
✨  Done in 0.68s.
```

最近のCLIは絵文字バリバリなのか…

新たに `yarn.lock` ファイルと `node_modules` ディレクトリができました。

```console
$ ls
node_modules	package.json	yarn.lock
```

### yarn.lock　ファイル

[yarn.lockファイル](https://yarnpkg.com/en/docs/yarn-lock)を見てみましょう。

```console
$ cat yarn.lock
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1


jquery@^3.1.1:
  version "3.1.1"
  resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.1.1.tgz#347c1c21c7e004115e0a4da32cece041fad3c8a3"
```

Rubyで言えば `Gemfile.lock` のような、依存性バージョンの正確な記録をとっているファイルというのがわかります。

実際開発する場合は、このファイルはバージョン管理に追加しておきましょう。

### node_modules/

インストールしたjQueryがここに入っています。

```
$ ls node_modules/
jquery
```

実際開発する場合はだいたいは `.gitignore` 行きのフォルダです。


### 実際にコード追加＋Webpackでビルドしてみる

jQueryだけでは何もできないので、JSのパッケージングなどのために `webpack` `webpack-dev-server` を `--dev` (開発用依存) で追加します。

```console
$ yarn add webpack webpack-dev-server --dev
```

[webpackの設定ファイル](https://webpack.github.io/docs/configuration.html)を追加します。（内容的には `./src/app.js` をソースに `./bundle.js` を出力とする感じ）

```js:webpack.config.js
module.exports = {
  entry: "./src/app.js",
  output: {
    filename: "bundle.js",
    path: __dirname + "/build"
  }
}
```

実コードを追加します。

```html:index.html
<script src="bundle.js"></script>

<body>
</body>
```

```js:src/app.js
$ = require("jQuery");

$(() => {
  $("body").text("Body has been loaded, yeah.");
});
```

開発用のローカルWebサーバ [webpack-dev-server](https://webpack.github.io/docs/webpack-dev-server.html) を立てます。

```console
$ yarn run webpack-dev-server -- --inline --hot

$ # webpack-dev-server の後ろの -- は　yarn run で起動するコマンドに対する引数の指定の明示のために必要。
$ # --inline: ホットリローディング用コード埋め込み方式の指定。inlineだとビルド結果のJSにホットリローディング用コードが差し込まれる。
$ # --hot: ホットデプロイを有効にする。
$ # マニュアル見るかぎり通常、両者を2つ指定しておけばよさげ。
```

サーバが起動したら、 http://localhost:8080 にアクセスして見てみましょう。

![image](https://qiita-image-store.s3.amazonaws.com/0/9619/ba77d37d-3211-e4a2-19a9-1f7e379f98fa.png)

ホットリローディングが有効になっているので、コードを書き換えて保存すれば画面が勝手に書き換わります。

1. ![image](https://qiita-image-store.s3.amazonaws.com/0/9619/9d20d598-c18b-3434-7a88-1bf0b9dfddd5.png)
2. ![image](https://qiita-image-store.s3.amazonaws.com/0/9619/3cb17002-f647-e83e-f831-ea274d641c52.png)

ちゃんとビルドする場合は単体のwebpackを起動しましょう。

```console
$ yarn run webpack
yarn run v0.17.10
$ "/Users/owner/test-yarn/node_modules/.bin/webpack"
Hash: f2cbb67337639c5656fd
Version: webpack 1.14.0
Time: 269ms
    Asset    Size  Chunks             Chunk Names
bundle.js  277 kB       0  [emitted]  main
   [0] ./src/app.js 91 bytes {0} [built]
    + 1 hidden modules
✨  Done in 0.61s.
```

## （おまけ） yarn のコマンド一覧ざっと見

https://github.com/yarnpkg/yarn/tree/0f1db96846badbbe3b43c470c05196eb29437fb4/src/cli/commands

### access

現在開発中のコマンドっぽい。謎。

```
Usage: yarn access [public|restricted|grant|revoke|ls-packages|ls-collaborators|edit] [flags]
```

### add / remove

パッケージへの依存性追加・削除。

https://yarnpkg.com/en/docs/cli/add
https://yarnpkg.com/en/docs/cli/remove


### bin

プロジェクト/node_modules/.bin フォルダをプリントするだけっぽい。

`yarn run webpack` は `$(yarn bin)/webpack ` というようにも書けるのでしょう。

https://yarnpkg.com/en/docs/cli/bin

### cache

Yarnのパッケージのキャッシュディレクトリ（macOSだと `~/Library/Caches/Yarn` ）のパスや中身を表示するようです。

https://yarnpkg.com/en/docs/cli/cache

### check

`package.json` とYarnのロックファイルの内容が一致しているかチェックします。 `--integrity` でパッケージのハッシュチェックもできるようです。

https://yarnpkg.com/en/docs/cli/check

### clean

`node_modules` ディレクトリからもはや要らないファイルを消し、 `.yarnclean` というファイル（要バージョンコントロール）を吐き出すようです。

https://yarnpkg.com/en/docs/cli/clean


### config 

`git config`　的なYarnの設定管理コマンド。

https://yarnpkg.com/en/docs/cli/config

### generate-lock-entry

`yarn.lock` にあたる内容を標準出力に出すっぽい。

https://yarnpkg.com/en/docs/cli/generate-lock-entry

### global

`yarn global add モジュール` が `npm install -g モジュール` 相当の動きをするっぽい。

ただ、PATHに `export PATH="$(yarn global bin):$PATH"` 相当をつけないと、おそらくそのまま実行するのは無理っぽい。

https://yarnpkg.com/en/docs/cli/global

### info

`yarn info パッケージ名` で該当パッケージの情報を表示。

https://yarnpkg.com/en/docs/cli/info


### init

対話式プロジェクト初期化用コマンド。

https://yarnpkg.com/en/docs/cli/init

### install

依存関係のダウンロード用コマンド。

https://yarnpkg.com/en/docs/cli/install


### licenses

`yarn licenses ls` で各依存パッケージのライセンスを表示。 

`yarn licenses generate-disclaimer` で各依存パッケージ全てのライセンスライセンス条項文を表示。

https://yarnpkg.com/en/docs/cli/licenses


### link / unlink

今いるパッケージディレクトリへのシンボリックリンクを、他のパッケージディレクトリの `node_modules/` の下に作成することができます。

https://yarnpkg.com/en/docs/cli/link


### login / logout

npm リポジトリへのログイン・ログアウト.


https://yarnpkg.com/en/docs/cli/login
https://yarnpkg.com/en/docs/cli/logout


### ls

現プロジェクトの依存ツリーを表示。

https://yarnpkg.com/en/docs/cli/ls


### outdated / upgrade / upgrade-interactive

`outdated`　で更新のあるパッケージを表示。 `upgrade` で更新をかける。

https://yarnpkg.com/en/docs/cli/outdated
https://yarnpkg.com/en/docs/cli/upgrade




### owner

レジストリ中のパッケージの所有者についての機能らしいですが、よくわかりませんでした。

https://yarnpkg.com/en/docs/cli/owner


### pack

プロジェクトを .tar.gz に固める。

https://yarnpkg.com/en/docs/cli/pack


### publish

npmにパッケージをぶち込む。

https://yarnpkg.com/en/docs/cli/publish


### run

`yarn add` などで追加したもののうちコマンド( `yarn run` か `ls $(yarn bin)` で確認可能)をこれ経由で実行するためのもの。 

https://yarnpkg.com/en/docs/cli/run


### self-update

Yarn自身のアップグレード。

https://yarnpkg.com/en/docs/cli/self-update


### tag

パッケージに対して、バージョン番号ではなく、かわりのタグ(`stable`とか)を指し示すためのコマンド。

https://yarnpkg.com/en/docs/cli/tag


### team

レジストリ中のパッケージのチームのメンバーシップ管理、とあるけれど、よくわかりません。

https://yarnpkg.com/en/docs/cli/team

### version

現プロジェクトのバージョン情報の変更。

https://yarnpkg.com/en/docs/cli/version

### versions

yarn および依存パッケージのバージョン番号の表示。

### why

直接依存・推移的依存など、どういう理由でそのパッケージに依存が発生しているのかを表示するためのコマンド。

```console
$ yarn why uuid

yarn why v0.17.10
[1/4] 🤔  Why do we have the module "uuid"...?
[2/4] 🚚  Initialising dependency graph...
[3/4] 🔍  Finding dependency...
[4/4] 🚡  Calculating file sizes...
info This module exists because "webpack-dev-server#sockjs" depends on it.
info Disk size without dependencies: "60kB"
info Disk size with unique dependencies: "60kB"
info Disk size with transitive dependencies: "60kB"
info Amount of shared dependencies: 0
✨  Done in 0.26s.
```

https://yarnpkg.com/en/docs/cli/why