YarnV2 こと Yarn@berry を試してみている

![image](https://4.bp.blogspot.com/-omczCJH0bZk/VD3SVPsbedI/AAAAAAAAoSM/4BRuYsgtxI0/s400/ojigi_animal_neko.png)

### Yarn とは
yarn とは雑には alternative npm。高速な Node.js 向けのパッケージマネージャ。
package.json を解釈し、高速にパッケージの依存解決を行ってくれる。

### Yarn V2 のインストール方法
Yarn v2 は現状 `yarn@berry` としてバージョンを指定することでインストール可能。

```sh:how-to-install.sh
# インストール済みの場合はまずアンインストールする
npm uninstall -g yarn
 
# v2 を使いたければタグを明示してインストールする
npm install -g yarn@berry
```

### V1 と V2 の違い
一次情報はこちらのエントリを参照のこと。スクショは公式から引用。
[https://dev.to/arcanis/introducing-yarn-2-4eh1](https://dev.to/arcanis/introducing-yarn-2-4eh1)

個人的に特に気になっているものに 🍎 (赤いリンゴ) をつけておく。
色々途中なので変化したり間違ってる部分はご容赦ください。

#### 🍏 CLI出力の改善
yarn v1 では絵文字が使われて可愛らしい出力だったが、v2 からは処理の具体的な内容を表示するように変化した。
色はアクセシビリティの関係でまだ変化するかもしれないらしい。
[![Image](https://res.cloudinary.com/practicaldev/image/fetch/s--FUMLyhUm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/qetNioL.png)](https://res.cloudinary.com/practicaldev/image/fetch/s--FUMLyhUm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/qetNioL.png)
出力には YN***** という番号が割り当てられ、この番号をもとに出力自体の情報を参照できるようになる、、、のかもしれない。

#### 🍏 ワークスペースに対応するCLI
ナンノコッチャという感じであるが、ワークスペース内でのパッケージの再利用を提案してくれる様子。
個人的には新しいやつを使っていきたいので解決済みの依存から引き出して古いバージョンを使うみたいなことはしないと思うが、容量を節約したいシーンには役に立つだろう。これはオプショナルな挙動になるようだ。
[![Image](https://res.cloudinary.com/practicaldev/image/fetch/s--TIJoZl_Y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/fVY7EAs.png)](https://res.cloudinary.com/practicaldev/image/fetch/s--TIJoZl_Y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/fVY7EAs.png)

#### 🍎 ゼロインストールへの対応
おそらく目玉機能。なんと実行しようとするスクリプトから依存を解決しつつ実行するという機能のようす。詳しい解説は [https://next.yarnpkg.com/features/zero-installs](https://next.yarnpkg.com/features/zero-installs) 参照のこと。
この機能のためか、`yarn add` しても node_modules ディレクトリは生成されない。従来の node_modules と同じ動きをさせたい場合は、[別途設定を必要とする。](https://yarnpkg.com/advanced/migration#if-required-install-the-node-modules-plugin)

#### 🍎 コマンド: yarn dlx (npx 相当のコマンド追加)
`npm` ではパッケージの取得と実行を同時にこなす `npx` というコマンドが標準で提供されている。
`yarn` にも今回同様の動きをする `yarn dlx` が追加された。語源は `download and execute` らしい。
`npx` とのスタンスの違いとしては 取得と実行を同時にこなすところは変化しないとして、リモートスクリプトの実行には `yarn dlx` を使い、ローカルスクリプトの実行には `yarn run` を使うという使い分けを行うそうだ。曰く、タイプミスでの意図しないスクリプト実行を起こす危険性があるということらしい。

#### 🍏 コマンド: yarn workspace foreach の追加
Yarn にワークスペースの概念が追加されたことによる機能の追加。
複数のリポジトリに対してコマンドを実行する場合外部コマンドを利用する必要があったが、このコマンドを利用すると yarn で制御を完結できるということらしい。細かくパッケージを分割して運用してるケースなどには便利なのかもしれない。`@something/hoge` みたいなパッケージ群で構成されるライブラリとかではコマンドの形式を揃えておくと役に立ちそう。

#### 🍏 新しいプロトコル: patch:
特定の依存に対してオレオレパッチを適用しつつパッチを当てる必要がある場合に利用できる。
従来パッケージインストール後に node_modules のスクリプトを魔改造するようなシーンもあったかもしれない。(本当はしないほうが良いとは思うが古の不思議な力によってそうなってしまっていることもあるだろう)
で、今回 yarn の動き的に基本的には node_modules を生成しないようになっているので、そういうやり方がそもそもできなくなっている。そういうときに役に立つのがこの patch を指定したインストール方法。

```json:sample-path-protocol.json
{
  "dependencies": {
    "left-pad": "patch:left-pad@1.3.0#./my-patch.patch"
  }
}
```
これで left-pad に my-patch.patch の差分を適用した状態でパッケージがインストールされる。

#### 🍏 新しいプロトコル: portal:
特定のディレクトリに対するシンボリックリンクを生成してくれる `link:` と似た動きをしてくれるらしい。ちなみに `link:` の場合は、任意のローカルディスク上のディレクトリへのシンボリックリンクを生成する。portal の場合は、逆にパッケージの任意のディレクトリへのシンボリックリンクを作成するということらしい。jQuery を yarn で持ってきて js だけコピーとかしなくて良くなるみたいな感じだろうか…？

#### 🍏 ワークスペースを考慮しつつのリリース
大規模プロジェクト向け機能らしい。Lerna というワークフローをサポートするパッケージを例に上げているが、それに似た機能が標準でついてくるということのようだ。個人的にはお世話になるシーンがなさそうなので省略。

#### 🍏 ワークスペースの制約
複数ワークスペースの依存を解決するための機能。同じく使わなさそうなので省略。
一部話題に上がっていた Prolog が使われている箇所というのがここの定義。

#### 🍏 ビルド依存関係の追跡
ネイティブビルドが発生するパッケージの再ビルドが必要なビルドパスを検知し、最小限を実行する仕組み。Yarn v1 では問題になっていたそうだが、そこまで問題になったことはあんまりないなぁという印象。
大規模なプロジェクトになるとそういう問題に当たりがちなのかもしれない。

#### 🍏 パッケージごとのビルド構成
dependencisMeta という定義を package.json に加えることで、パッケージのビルドを行うか行わないかみたいなスイッチができるようになる。デフォルトだと全部実行する。めったに使うシーンなさそう。

#### 🍎 正規化された実行環境
従来、特に Windows で package.json の scripts を実行したときには bash で実行されないので環境変数の指定などで動かないなどクロスプラットフォーム開発上の問題が起こっていた。

```json:cannot-run-on-windows.json
{
  "scripts": {
    "redirect": "node ./something.js > hello.md",
    "no-cross-env": "NODE_ENV=prod webpack"
  }
}
```
Yarn2 では npm scripts の実行に独自のインタプリタが導入されておりそういう問題にはまらないように設計されているということらしい。WSLも何もなくて Windows上に Node.js と yarn V2 をインストールしている場合はポータビリティが上がって良さそう。任意の引数の展開などにも対応する。
便利な一方で、 npm にはそんな機能はないので当然ながらこの機能を使用するとnpm との互換性がなくなる。

```json:yarn-scripts-sample.json
{
  "scripts": {
    "lint-and-build": "yarn lint \"$@\" && yarn build \"$@\""
  }
}
```
#### 🍏 peerDependencies の依存解決の改善
peerDependencies がうまく動かない場合があったのが改善されたらしい。
Yarn v2 を使うことで Plug'n'Play が十全に機能するためということらしい。

#### 🍎 ロックファイルのフォーマット変更
はい、破壊的変更です。`yarn.lock` は従来 YAML で構成されていたが、これが syml という亜種になり機能が限定された代わりに高速になったらしい。中身もだいぶ変化している。yarn V1 と V2 の間で yarn.lock に互換性はないとみたほうが良さそう。

#### 🍎 TypeScript に実装が変わりました
使う文には影響ないけど実装が TypeScript になりました いうこと。

#### 🍏 モジュラーアーキテクチャの採用
yarn 自体をプラグインで拡張できるようになったそうな。TypeScript への移行はこのプラグインを書くときに補完が効いたりとかで便利になったということなのだろう。型定義は `@types/yarn` で取得できるらしい。

#### 🍏 正規化された設定
yarn V1 では npm との互換性を重視したために yarn の設定はどこに書けばいいのかわからないというフィードバックが多数寄せられたとのことで、yarn V2 からは `.yarnrc.yml` というファイルに書けばOKとなったとのこと。V1にも`.yarnrc`ってあるじゃん？とは思うけどそういうことではないのかもしれない・・・。V1で `.yarnrc` を必要とする使い方をしていた場合は移行が必要になる。
[https://legacy.yarnpkg.com/lang/ja/docs/yarnrc/](https://legacy.yarnpkg.com/lang/ja/docs/yarnrc/)

#### 🍎 厳密なパッケージ管理
大きな変化の１つ。package.json の depencencies に定義されていないパッケージは yarn V2 で依存を解決し、実行するコードにおいては利用できないようになった。Plug'n'Play の依存解決によるものらしい。よってなんらかの依存の依存によってインストールされているパッケージを利用していた場合は明示的にインストールが必要になる。

#### 🍏 bundleDependencies の廃止
こういうのもあったのねという感じ。使ったことがなかったので省略。
[移行ガイド](https://next.yarnpkg.com/advanced/migration) を参照して代替え手段を見つけるべし。

#### 🍎 パッケージは読み取り専用に
パッケージの依存解決の際に基本的に node_modules に展開しなくなったので、必然的にパッケージの魔改造ができなくなった。どうしてもその必要がある場合は、patch: プロトコルを使用するか、あるいは従来どおりに展開してもらえるよう設定を行う必要がある。

### いくつかやってみた
#### 拡張された npm-scripts
yarn 独自のインタプリタを活用するとこんなふうなスクリプトを実行できる

```json:double-echo-package.json
{
  "scripts": {
    "double-echo": "echo \"$@\"; echo \"$@\""
  }
}
```
yarn での実行結果はこのようになる

```sh:result-double-echo-yarn.sh
$ yarn run double-echo hogehoge
hogehoge
hogehoge
```
npm で実行してしまうとこうなる。

```sh:result-double-echo-npm.sh
$ npm run double-echo hogehoge
> echo "$@"; echo "$@" "hogehoge"
hogehoge
```
yarn と npm の完全な互換性を期待して yarn と npm を混在させていた場合は、こういう違いが出てくるので気をつける必要がある。

#### node コマンドでのスクリプトの実行
yarn V2 で依存を解決している状態の場合、Node.js 自身でパッケージを参照できなくなる。なんてこったい。
そのため、代替として `yarn node` を実行する必要がある。こうすることで yarn で独自に解決した依存を利用できるということのようだ。
下記は yarn V2 で依存を解決したあとのフォルダツリー。依存として chalk を追加したあとの状態のもの。見てわかると思うが慣れ親しんだ node_modules が存在しない。代わりに `.yarn/cache` というディレクトリができていてそこに zip が複数配置されている。スクリプト実行時に必要になったタイミングでこの zip を展開して実行しているということのようだ。
[![Image](https://gyazo.com/45ec36738b5949f0b0a491cac0419884/thumb/1000)](https://gyazo.com/45ec36738b5949f0b0a491cac0419884)

### V1 から V2 への移行方法は？
[https://yarnpkg.com/advanced/migration](https://yarnpkg.com/advanced/migration) を見るべし。
ちなみに手元のアプリを何もせずそのまま yarn.lock を吹き飛ばして再構築したところ動かなかったので、がんばりがそこそこ必要になりそうだ。別途やったことはまとめるかもしれない。

### まとめ
Yarn V2 は ZeroInstall と  Plug'n'Play をベースにしたパッケージマネージャに生まれ変わり、単なる高速な npm との互換性を維持したツールと言う立ち位置を卒業するようす。 dev.to の記事の書き方からもそういう雰囲気を感じ取れた。
高速な npm を求めていた層からは、ちょっとそれどうなのという感じもなくはないようで、例えば[このIssueでは](https://github.com/yarnpkg/berry/issues/766) 大幅な変化があったことからそのまま yarn の更新としてリリースするのはどうなのか？みたいな議論がされている。しかしながら基本的には `yarn` の正当な後継としてリリースされるようだ。
もとの node_modules の仕組みも考えさせられる部分はあると思うので現状が最高というわけでも多分ないのでそういうのをまとめてひっくるめていい方向に進むきっかけに yarnV2 がなってくれるといいなと感じた。

> from [Scrapbox](https://scrapbox.io/dojineko/YarnV2_%E3%81%93%E3%81%A8_Yarn@berry_%E3%82%92%E8%A9%A6%E3%81%97%E3%81%A6%E3%81%BF%E3%81%A6%E3%81%84%E3%82%8B)