• 作成:

yarnをcorepack管理とclassic(v1)が使われているプロジェクトで自動的に使い分ける

yarn v4がリリースされました

ちょっと前に知ったんですがyarn v4が10月23日に正式リリースされていました。

Release: Yarn 4.0 🪄⚗️ | Yarn

前にyarn v4からはバンドルされたJavaScriptプログラムであるreleasesやpluginsをGitにコミットする必要が無くなります - ncaqという記事を書きました。

この記事に書いてある通り、 yarn v4ではyarn berry(v2以後)に感じていた問題が解決されていました。その時v4が正式リリースされたら移行しようと考えていたため移行します。

その時に少しだけ躓いた問題をメモします。

勝手にプロジェクトがマイグレーションされてしまう問題

私は~/.local/binPATHに追加してユーザスペースでインストールするプログラムはそこに置いてあるので、 corepackでインストールする場合以下のようなコマンドを実行します。 corepackはNode v14から追加されています。

corepack enable --install-directory ~/.local/bin npm yarn

私はGentoo LinuxのnodejsのUSEフラグで、 corepackを有効にして競合するnpmのUSEフラグを無効化しているため、 npmもcorepack管理しています。 pnpmとかも有効化出来ますがとりあえず今は使ってないのでスルーしています。

しかしyarn v3の頃は問題なかった気がするのですが、この方法でcorepackでプロジェクトに依存しないグローバルにインストールしてyarnコマンドを使うと、そのプロジェクトがyarn classic(yarn v1)で管理されていると自動でyarn v4にマイグレーションされてしまいます。

自分のプロジェクトなら流石にそろそろberryに移行するのでそれを機会にマイグレーションしても良いのですが、他人がGitHubにホストしてるプロジェクトにちょっとしたPRを出すときに、「ついでにyarn berryに移行しておきました」と出すのは流石に気が引けます。

理想の動きとしてはberry移行しているプロジェクトでは指定されたバージョンのパッケージマネージャを使って、 yarn classicを使っているプロジェクトではyarn classicを使うようにしたいです。

corepackを使わずyarnパッケージを使うのはダメ

ではcorepackを使うのをやめて、 Gentooが提供するyarnパッケージを使えば良いのではと考えました。

yarn v1は、 yarn v2にまつわる誤解 | Wantedly Engineer Blogに書かれてあるように、新しいyarnのブートローダとして使えます。今それをcorepackとして分離していて一応corepackはまだExperimentalなのでそれでも良いかなと考えました。

しかしそれはそれで問題があります。

corepackで管理されていると、 corepack is 何?に書かれてあるように、 package.jsonに、

"packageManager": "yarn@4.0.1"

のように書いてあれば自動でyarn v4が使われるのですが、 yarnのブートローダ機能に頼る場合はそれは使えません。

その場合、 .yarnrc.ymlに、

yarnPath: .yarn/releases/yarn-4.0.1.cjs

のように書かれてそれが読み込まれることになるのですが、そうなると.yarnディレクトリを消すとyarnが実行できなくなってしまうため、先の私の記事で書いたようにバンドル済み実行プログラムをgitにcommitする必要が発生してしまいます。

corepackでグローバルにはyarn classicをインストールする

これの解決方法は簡単です。 corepackを使ってグローバルにはyarn classicをインストールして、プロジェクトごとにパッケージマネージャをyarn set version stableなどで指定すれば問題ありません。

具体的には以下のようにします。

# corepackでnpmとyarnを管理する。
corepack enable --install-directory ~/.local/bin npm yarn
# グローバルでは勝手にマイグレーションを行わないようにyarn classicを利用する。
corepack prepare yarn@1 --activate

自分はこれをyarn-install-world実行スクリプトに含めて、 yarn global addでprettierをインストールするついでに事前実行しています。

これでyarn classicが使われているプロジェクトではyarn classicが使われ、 corepackでパッケージマネージャを管理しているプロジェクトではそれが使われるようになりました。