❤️‍🩹

Bunでパッチを当てるためにpatch-packageを動かす方法

2024/03/31に公開

Turborepo + Bun + ElysiaJS + Nextのモノレポ構成を試していたらパッチが必要になる場面に出くわしたので、その対処法を共有します!

色々試してみた結果、patch-packagepatch-package自体をパッチして、呼び出されるパッケージマネージャーをyarnからbunに書き換えると、うまく動作することがわかりました。(yarnなしのローカル環境、GitHub Actions、Vercelで動作確認済みです!)

手順

1. BunでYarnのロックファイルを生成するように設定する

bun install --yarnのように--yarnフラグを指定するか、以下の行をbunfig.tomlに追加して、yarn.lockファイルを生成するようにします。

これは、現在patch-packageがBunのバイナリロックファイル形式をサポートしていないため必要です。(https://github.com/ds300/patch-package/issues/489 参照)

[install.lockfile]
print = "yarn" # bun.lockbと並行して非Bunロックファイルを生成するかどうか

[!WARNING]
依存関係を更新するたびにYarn v1のロックファイルを生成する必要があるため、個人的には後者のオプションをおすすめします。

2. patch-packageをインストールする

patch-packageを開発依存関係に追加します。

bun add -D patch-package

3. patch-packageのソースファイルを手動で変更する

node_modules/patch-package/dist/makePatch.jsを開き、yarnを呼び出しているspawnSafe_1.spawnSafeSyncを探して、以下のdiffのようにbunに置き換えます。

diff --git a/node_modules/patch-package/dist/makePatch.js b/node_modules/patch-package/dist/makePatch.js
index d8d0925..874284a 100644
--- a/node_modules/patch-package/dist/makePatch.js
+++ b/node_modules/patch-package/dist/makePatch.js
@@ -120,7 +120,7 @@ function makePatch({ packagePathSpecifier, appPath, packageManager, includePaths
   try {
     // try first without ignoring scripts in case they are required
     // this works in 99.99% of cases
-    spawnSafe_1.spawnSafeSync(`yarn`, ["install", "--ignore-engines"], {
+    spawnSafe_1.spawnSafeSync(`bun`, ["install"], {
       cwd: tmpRepoNpmRoot,
       logStdErrOnError: false,
     });
@@ -128,7 +128,7 @@ function makePatch({ packagePathSpecifier, appPath, packageManager, includePaths
   } catch (e) {
     // try again while ignoring scripts in case the script depends on
     // an implicit context which we haven't reproduced
-    spawnSafe_1.spawnSafeSync(`yarn`, ["install", "--ignore-engines", "--ignore-scripts"], {
+    spawnSafe_1.spawnSafeSync(`bun`, ["install", "--ignore-scripts"], {
       cwd: tmpRepoNpmRoot,
     });
   }

[!NOTE]
現在、Bunはpackage.jsonenginesフィールドをサポートしていないため、--ignore-enginesフラグを削除しても問題ありません。(https://github.com/oven-sh/bun/issues/5846 参照)

4. 作成したパッチをpatches/に保存する

以下のコマンドを実行して、パッチファイルを作成します。

bun patch-package patch-package

これで、patches/patch-package+8.0.0.patchが作成されるはずです。

5. package.jsonpostinstallスクリプトを追加する

patch-packageのドキュメントに記載されているように、以下のスクリプトをpackage.jsonに追加します。

{
  "name": "reoiam-dev",
  "version": "0.0.0",
  "workspaces": [
    "apps/*",
    "packages/*"
  ],
  "scripts": {
    "postinstall": "patch-package"
  }
}

6. 目的のパッケージにパッチを適用する

bun patch-package your-package-name

また、git clean -dfX && bun iを実行して、正常に動作していることを確認してください。

これがお役に立てば幸いです!👀


例となるコミット:
https://github.com/ReoHakase/reoiam-dev/pull/122/commits/2c016376918356d46ae59a2199e687aec085fb76
https://github.com/ReoHakase/reoiam-dev/pull/122/commits/8aae34e0c072b389b165a04870ba9a631355d1a6

Discussion