水芭蕉

pnpm でパッケージにパッチを当てる

`pnpm patch` コマンドを使うと、依存パッケージのコードを直接書き換えることができます。

pnpm patch コマンドを使うと、依存パッケージのコードを直接書き換えることができます。例えば依存パッケージにバグがあった場合、プルリクエストを送って修正を提案する方法が最適ですが、提案した修正がマージされるまでタイムラグがあるでしょう。今すぐにバグを回避したい場合には、一時的に依存パッケージを直接修正する方法を取ることになるでしょう。

ですが node_modules ディレクトリ中のソースコードに直接修正を加えると、新たなパッケージを追加する目的などで npm install コマンドを実行したタイミングで修正内容が消えてしまいます。また、一般的に node_modules ディレクトリは git の管理下に置かれていないため、修正したパッケージをバージョン管理できません。

pnpm patch コマンドを使うと修正した内容は patches ディレクトリで管理されるため、上記のような問題を回避できます。

使い方

例として is-odd パッケージの isOdd 関数の挙動を変更してみます。引数に文字列の数字(例: "1")を渡した場合に例外を投げるようにします。

まず、is-odd パッケージをインストールします。

pnpm install is-odd

続いて pnpm patch <pkg> コマンドを実行します。<pkg> は修正したいパッケージの名前を指定します。

pnpm patch is-odd

このコマンドを実行すると一時ディレクトリにパッケージが展開されます。私の環境で実行した場合、/private/var/folders/39/htskyvkd6vg8ck_hc87n9ck40000gn/T/ecaff011e92c1418ee41d41dce2a3f0b/user というディレクトリに展開されました。

pnpm patch is-odd
You can now edit the following folder: /private/var/folders/39/htskyvkd6vg8ck_hc87n9ck40000gn/T/ecaff011e92c1418ee41d41dce2a3f0b/user

コンソールに表示された一時ディレクトリに移動して、index.js ファイルを修正します。

index.js
  /*!
   * is-odd <https://github.com/jonschlinkert/is-odd>
   *
   * Copyright (c) 2015-2017, Jon Schlinkert.
   * Released under the MIT License.
   */
 
  'use strict';
 
  const isNumber = require('is-number');
 
  module.exports = function isOdd(value) {
+   if (typeof value !== 'number') {
+     throw new TypeError('expected a number');
+   }
    const n = Math.abs(value);
    if (!isNumber(n)) {
      throw new TypeError('expected a number');
    }
    if (!Number.isInteger(n)) {
      throw new Error('expected an integer');
    }
    if (!Number.isSafeInteger(n)) {
      throw new Error('value exceeds maximum safe integer');
    }
    return (n % 2) === 1;
  };

修正が完了したら、pnpm patch-commit <path> コマンドを実行してパッチファイルを生成します。<path> は先程修正した一時ディレクトリのパスを指定します。

pnpm patch-commit /private/var/folders/39/htskyvkd6vg8ck_hc87n9ck40000gn/T/ecaff011e92c1418ee41d41dce2a3f0b/user

コマンドを実行すると patches ディレクトリが生成され、is-odd@3.0.1.patch というパッチファイルが配置されます。

is-odd@3.0.1.patch
diff --git a/index.js b/index.js
index 79d1f22a8e7a27efb8841bb83cb682ea1ff3a59c..af66fefe7a0292163d1269c2276bc2a245a5bedc 100644
--- a/index.js
+++ b/index.js
@@ -10,6 +10,9 @@
 const isNumber = require('is-number');
 
 module.exports = function isOdd(value) {
+  if (typeof value !== 'number') {
+    throw new TypeError('expected a number');
+  }
   const n = Math.abs(value);
   if (!isNumber(n)) {
     throw new TypeError('expected a number');

また、packges.json ファイルでは patchedDependencies フィールドが追加されていて、パッチファイルのパスが指定されています。このフィールドにより指定したパッケージがパッチファイルを適用すべきことが pnpm に伝えられます。

package.json
{
  "dependencies": {
    "is-odd": "^3.0.1"
  },
  "pnpm": {
    "patchedDependencies": {
      "is-odd@3.0.1": "patches/is-odd@3.0.1.patch"
    }
  }
}

pnpm patch-commit コマンドを実行したあとは pnpm install コマンドを実行することなく、即座に修正内容が適用されます。main.js ファイルを作成して試してみましょう。

main.js
import isOdd from "is-odd";
 
console.log(isOdd("1"));

このファイルを実行すると、例外が投げられることが確認できます。

node main.js 
/node_modules/.pnpm/is-odd@3.0.1_4wdwvtmrrmomug63a56tqryyhy/node_modules/is-odd/index.js:14
    throw new TypeError('expected a number');
          ^
TypeError: expected a number

Contributors

> GitHub で修正を提案する
この記事をシェアする
はてなブックマークに追加

関連記事