corepack を使ってプロジェクト内で使用する pnpm/yarn のバージョンを管理する

corepack とは

Node.js の実行環境には、パッケージマネージャーとして標準で npm コマンドが搭載されていますが、npm の代わりに yarnpnpm などを導入しているプロジェクトが多くあります。 従来は、これらのコマンドを npm install -g pnpm のように別途インストールする必要がありましたが、Node.js に標準搭載された corepack の仕組みを使用すると、初めからインストールされているかのようにyarnpnpm コマンドを実行できるようになります。

corepack が使用するパッケージマネージャーは、package.jsonpackageManager プロパティで宣言しておくことができるので、プロジェクト内で使用するパッケージマネージャーとそのバージョンを統一できます。

☝️ ワンポイント package.jsonpackageManager フィールドはプロジェクトが使うパッケージマネージャーとそのバージョンを宣言しているだけで、このフィールドは corepack 専用のフィールドというわけではありません。 あくまで、システムの Node.js 環境で corepack が有効化されている場合に、このフィールドの内容に基づいて yarnpnpm のバージョンが自動制御される、ということです。

最初の準備(既存の yarn/pnpm の削除と corepack の有効化)

もし、npm installbrew でグローバルインストールした yarnpnpm がある場合は、もう必要ないのでアンインストールしておきましょう。

不要な yarn や pnpm はアンインストール
$ npm uninstall -g yarn
$ npm uninstall -g pnpm
$ brew uninstall yarn
$ brew uninstall pnpm

corepack コマンドは Node.js 環境に組み込まれていますが、Node.js 21 の時点ではまだ実験段階 (experimental status) のため、corepack enable コマンドを実行して明示的に有効化 (Opt-in) しておく必要があります。 このコマンドは、システム内で一度だけ実行すれば大丈夫です。

corepack によるパッケージマネージャー管理を有効化
$ corepack enable

このコマンドを実行することで、node コマンドの実行ファイルが置かれたディレクトリ内に、yarnpnpm などのシンボリックリンクが生成されます。 これで、システム全体で yarnpnpm コマンドを実行できるようになります。

各パッケージマネージャーのコマンド(シンボリックリンク)が、node と同じ場所に存在していれば、おそらくうまくいっています。

$ which node npm yarn pnpm
/Users/maku/.nvm/versions/node/v21.6.1/bin/node
/Users/maku/.nvm/versions/node/v21.6.1/bin/npm
/Users/maku/.nvm/versions/node/v21.6.1/bin/yarn
/Users/maku/.nvm/versions/node/v21.6.1/bin/pnpm

ここで表示されるパス内の v21.6.1 という部分は、yarnpnpm コマンドのバージョンとは関係ないことに注意してください。

プロジェクト内で使用する yarn や pnpm のバージョンを指定する

corepack 経由の yarnpnpm を使用する場合、package.json ファイルの packageManager プロパティで、使用するパッケージマネージャーとそのバージョンを定義しておくことができます。 ここでは、テスト用の Node.js プロジェクトを作って設定してみます。

テスト用のアプリを新規作成(package.json を生成)
$ mkdir myapp && cd myapp
$ npm init -y

プロジェクト内で使用するパッケージマネージャーは、corepack use コマンドで指定します。

使用するパッケージマネージャーを定義
$ corepack use npm@*   # npm の最新版を使う場合
$ corepack use npm@10  # npm バージョン 10.x.x を使う場合

$ corepack use yarn@*  # yarn の最新版を使う場合
$ corepack use yarn@4  # yarn バージョン 4.x.x を使う場合

$ corepack use pnpm@*  # pnpm の最新版を使う場合
$ corepack use pnpm@9  # pnpm バージョン 9.x.x を使う場合

例えば、パッケージマネージャーとして pnpm を使うよう指定した場合、package.json ファイルに次のように記録されます。

package.json
{
  "name": "myapp",
  "version": "1.0.0",
  // ...
  "packageManager": "pnpm@9.0.0+sha512.b4106707c7225b174...(省略)..."
}

カレントディレクトリに package.json が存在しない状態で corepack use pnpm@9 を実行すると、以下のような packageManager フィールドのみが存在するファイルが自動生成されます。

package.json
{
  "packageManager": "pnpm@9.0.0+..."
}

この状態で、pnpm コマンドを実行すると、指定したバージョンの pnpm が起動するはずです。

$ pnpm --version
9.0.0

あとは、通常通り yarnpnpm コマンドを使ってパッケージ管理していけば OK です。

$ pnpm add dotenv

使用する pnpm のバージョンは package.json に記述されているので、チーム内の他のメンバーが pnpm コマンドを実行するときも同じバージョンが使われるようになります。

他のメンバー(や CI/CD)の環境でビルドするとき
$ corepack enable  # (システム内で一度だけ実行)
$ pnpm install     # 指定された pnpm バージョンを使って依存パッケージをインストール
$ pnpm build       # build スクリプトの実行

プロジェクト内で使用する pnpm のバージョンを更新したいときは、新しいバージョンを corepack use で指定すれば OK です(package.jsonpackageManager の項目が更新されます)。

pnpm をバージョンアップ(package.json を自動更新)
$ corepack use pnpm@10

# 下記でも package.json を更新してくれるけどハッシュコードが付かないっぽい
$ pnpm self-update