patch-package を使ってnpmパッケージに安全にパッチを当てる方法

August 06, 2021

初めまして! N Inc. 共同創業者でエンジニアの北方(@Yk_0n)です。

今回は、npm パッケージに安全にパッチを当てることができる patch-package というツールを紹介したいと思います!

前回の記事をまだご覧になっていない方は、ぜひこちらもご覧ください!

GitHub Actions を使って push だけで npm に公開 & CHANGELOG 更新する仕組みを作ろう!

https://dev.blog.n.inc/2021-04-26-semantic-release/

patch-package とは

patch-package とは、npm パッケージに安全にパッチを当てることができるツールです。弊社でもフロントエンドのパッケージなどのパッチに使用しています!

https://github.com/ds300/patch-package

patch-package を使うメリット

npmパッケージにパッチを当てたいとなった時に、patch-packageを使わない方法としては、

  • 手動でpatchを作成し適用する
  • forkしてgitからインストールする

の2つがあるかと思います。

まず、1つ目の「手動でpatchを作成し適用する」の方法だと、npmパッケージのバージョンが変化した際に確認が難しくなる、チームでパッチを適用してもらう必要があるなどのデメリットがあります。

2つ目の「forkしてgitからインストールする」では、npmパッケージが公式ではないため、Dependabotなどのアップデート情報を自動取得するのが難しいというデメリットがあります。

これらの方法でデメリットとして挙げた問題については、patch-packageを使用することで解決することができます。

patch-package の使い方

早速ですが、patch-packageの使い方を紹介していきたいと思います。

インストール

まず、以下のコマンドでpatch-packageをインストールします。

npmの場合

npm i patch-package

yarnの場合

yarnの場合、 postinstall-postinstall というパッケージが必要になります。 これは、yarn特有の yarn addyarn remove 時に postinstall が呼び出されない動作を修正するためです。

yarn add patch-package postinstall-postinstall

いずれの場合も、フロントエンドなどでプロダクションの環境ではnpmパッケージにパッチを当てる必要がない場合は devDependencies でも問題ありません。

インストールが完了したら、 package.jsonscripts に以下を追加します。

"scripts": {
  "postinstall": "patch-package"
}

postinstallpatch-package を呼び出すことで、インストールされるたびに、対象のnpmパッケージにパッチを適用してくれます。

npmパッケージの編集

まず、パッチ前のnpmパッケージを、npmyarn を用いて通常通りインストールします。

次に、 node_modules 配下にインストールされた対象のパッケージを編集します。

今回はデモとして、 axios のパッケージにパッチを当ててみたいと思います。

まずは、axios のファイルを探すため、 node_modules/axios/package.json を開いてみると、 index.js がエントリーポイントであることがわかります。

axiosのpackage.json

今回は、エントリーポイントの index.jsconsole.log を追加して書き換えられているか確認することにします。

axiosを編集

画像のように、エントリーポイントに console.log("patched!"); を追加してみました。

axiosを編集

この状態で、 axios をインポートすると、以下の画像のように patched! と表示されます。

編集したaxiosを呼び出す

このような感じで、 node_modules 配下のオリジナルのnpmパッケージを編集します。

パッチを生成する

npmパッケージを編集したら、以下のコマンドを実行します。

npm run patch-package <パッケージ名>

もしくは

yarn patch-package <パッケージ名>

このコマンドを実行することで、 patch-package がオリジナルのパッケージとローカルの node_modules を比較し、patchを自動生成してくれます!

今回は、 axios のパッチを生成するので yarn patch-package axios を実行してみます。

patch-package実行結果

成功すると、patches/<npmパッケージ名>+<バージョン>.patch にパッチが生成されます!

生成されたパッチ

patch-package <npmパッケージ名> を実行するだけで、サクッとパッチが生成できるのも patch-package の魅力です!

パッチが適用されるか確認する

生成したパッチがきちんと適用されるか確認してみます。

一度、 以下のコマンドで node_modules を削除して再度インストールしてみます。

rm -rf node_modules

削除したら npm install もしくは yarn install を実行して、通常通り npmパッケージをインストールしてみます。

yarn install

すると、画像のように、パッチを適用したよ!と表示されるはずです。

この状態で、axios をインポートすると、先ほどの変更が適用されていることがわかります!

編集したaxiosを呼び出す

npmのバージョンが変化した場合

パッチを生成したnpmパッケージのバージョンが、パッチ生成時と異なる場合の挙動を検証してみます。

試しに、 先ほど試した axios のバージョンと異なる [email protected] をインストールしてみると、以下のように表示されます。

バージョンミスマッチ

今回は問題なくパッチが適用されたため、警告として表示されています。

このように、バージョンが異なる場合もパッチが適用できる場合は、警告を表示しつつパッチを適用してくれます。

パッチが適用できない場合は、ローカル環境ではデフォルトで正常終了、CI環境では異常終了(exit 1)するようになっているようです。

この挙動は --error-on-fail オプションで変更が可能です。

まとめ

今回は、 patch-package の紹介と簡単な使い方を紹介しました。この機能のバージョンを使用したいけど、一部分だけバグっているなどの場合に、かなり役立つツールだと思います。

使用しているnpmパッケージにパッチを当てたいな〜という時には、patch-packageの存在を思い出してみてください!

一緒に働きませんか?

N Inc.では、「現実世界をモデル化する」エンジニアを募集しています。

詳しい情報については、特設サイトをご覧ください!

エンジニア採用特設サイト