💨

corepack でモジュールごとに npm クライアントを指定する

2022/02/02に公開

tl;dr

  • node 14.19.0 で npm のバージョンを明示的に切り替える corepack が入った
  • 現状の npm-cli 自体が corepack に対応してないので、有効にしたければ npm コマンド自体を corepack に移す必要がある
  • 現時点で packageManager を指定するだけだとまだ他の環境で有効にならないが、将来的に npmnode の corepack 対応が行き渡った時点で段階的に有効になる。

もっと詳しく

# 手元の node を v14.19.0 以上に更新する
# 自分は nvm で入れてたのでこう
$ nvm install v14.19.0

# グローバルに入れた npm, pnpm, yarn を消さないとパス優先度次第で働かないので消す
$ npm uninstall -g npm pnpm yarn
# この時点で npm コマンドは使えなくなってる

# corepack から enable すると corepack 管理の npm, pnpm, yarn が生える
$ corepack enable npm pnpm yarn

# この時点で node にプリインされたデフォルトの npm が復活している
$ npm -v 8.3.2

(npm 本体がどう振る舞っているか自信がない。npm を復活させる前に corepack prepare npm@8.3.2 --activate とかしておく必要があるかも)

ここからが本番。 package.json ごとに npm クライアントを明示的に指定する

mkdir foo && cd foo

code foo/package.json
{
  "packageManager": "npm@6.29.0"
}
# この package.json を親に持つディレクトリで npm を使うと指定されたバージョンになる
$ npm -v
6.29.0

# pnpm や yarn 等は使えなくなっている(のを実際は corepack が管理している)
$ pnpm
Usage Error: This project is configured to use npm
$ yarn
Usage Error: This project is configured to use npm

$ cd .. # package.json を持つディレクトリの外に出る

$ npm -v
8.3.2

pnpm や yarn を使いたければ corepack に管理させるとよい。が、npm と違って packageManager を見る実装がすでに入ってるので、npm ほど問題にはなりにくい。

なぜ corepack を使うべきか

集団開発時に yarn を使っているつもりでも npm を使う人が混ざって、正しくない状態のまま push されることがある。

また、npm だけを使っているつもりでも v6 と v8 の非互換を踏んでしまうことがあり、今の node の周辺環境だと package.json の engines 指定はカジュアルに無視されていることもあり気を抜くと混ざりがち。npm ci で検知できるものもあるが、これすら npm の出来の悪さのせいで外さざるを得ないときがある。(手順次第で optional な環境固有のバイナリを lock してるときがある…)

これを corepack で解消できる。npm iyarn install にフォールバックするわけではないが、少なくとも corepack が入っていれば npm install してしまうミスを検知できる。

…といっても現状入れたところで、集団開発時に「このエラーなんですか?」という問い合わせがなくなるわけではないだろうが、間違った状態が push されるよりはマシなので、将来的に全員に行き渡って npm 本体も対応したときを見越して、現状害があるわけでもないので優先的に入れておくと良さそう。

Discussion