notebook

都内でWEB系エンジニアやってます。

patch-packageでpatchをコード管理する

ちょうどプライベートで開発しているものでモジュール側のソースをどうしてもいじらないといけなそうな場面に遭遇したためすこししらべたら面白そうなモジュールを見つけたので使ってみた話

patch-package

ds300/patch-package: Fix broken node modules instantly 🏃🏽‍♀️💨

github.com

その名の通りパッチを管理できるnpmモジュールです

install, 設定

npm install --save-dev patch-package
  • package.json
"scripts": {
  "postinstall": "patch-package"
}

npm scriptsのフックを使うということのよう

postinstallnpm install後に特定コマンドを実行できるようになる

なので複数人で開発したときでもnpm installをしたら自動でパッチが当たるようになる

コードの修正

ServerlessFrameworkでTypeScriptのプラグインを入れたもののLayerとの相性がよくないよう

パス周りでうまく動いていなかったようなのでとりあえず動かすことを目的に何度かnode_modules以下のファイルを直接いじって修正してみた

汎用的に使える内容ではないので(+これで一応動いたけど自信なし)プロジェクト内でパッチ管理する

ということで用途的にはバッチリな気がする

diff --git a/node_modules/serverless/lib/plugins/package/lib/packageService.js b/node_modules/serverless/lib/plugins/package/lib/packageService.js
old mode 100644
new mode 100755
index 1771ce3..7cc404c
--- a/node_modules/serverless/lib/plugins/package/lib/packageService.js
+++ b/node_modules/serverless/lib/plugins/package/lib/packageService.js
@@ -242,6 +242,13 @@ module.exports = {
     // NOTE: please keep this order of concatenating the include params
     // rather than doing it the other way round!
     // see https://github.com/serverless/serverless/pull/5825 for more information
+    const rootDir = this.serverless.config.serverlessPath.replace(/\/node_modules\/serverless\/lib/, '');
+    if (prefix && prefix.match(/puppeteer_layer_dist/)){
+      this.serverless.config.servicePath = `${rootDir}`;
+    }
+    else {
+      this.serverless.config.servicePath = `${rootDir}/.build`;
+    }
     return globby(['**'].concat(params.include), {
       cwd: path.join(this.serverless.config.servicePath, prefix || ''),
       dot: true,

パッチファイルを作成

npx patch-package serverless

今回はserverlessの中身を修正したので上記コマンドでパッチを作成する

patchesディレクトリの中にパッチファイルが生成される

tmpディレクトリでnpm installしてから既存のパッケージと差分取ってパッチファイルを生成しているっぽい

また、生成されたファイル名にバージョンが入っているので該当バージョンのときのみ適用される

patches/serverless+1.52.0.patch

なのでバージョンを上げる毎にパッチの見直しをする必要がある、まぁ当然といえば当然ですね

まとめ

ということで、下記用途で使うと良さそうだなという感じに思いました

  • PR出してマージされる(リリースされる)までのつなぎとしての使用
  • 開発が活発ではないモジュールでの使用
  • プロジェクト固有事情でどうしても修正が必要な場合の使用

パッチだらけになるのはちょっと。。。って感じではあるもののPR出したりするには汎用的な内容の修正じゃないとapproveしてもらえないだろうし送ったPRがマージされてリリースされるまでには当然時間がかかります

修正したものがリリースされるまでのつなぎとしてはとても使い勝手が良いものだと感じました

開発が活発じゃないパッケージだったりするとPRだしてもマージされないみたいなパターンはあると思うのでそういう場合にも使えそうですね

また、個人的にはこれあるしちょっとモジュール側のコードいじってみようかなという気持ちになるかなと思いました(個人開発なら)

まぁ多用してしまうと半年、1年後などに地獄を見る気がするのでご利用は計画的にといった感じでしょうか

あとは今回はじめて知ったnpmのpre/post hookは色々活用パターンあると思うので別途で調べてみようかと思いました

他の言語でもこういうのほしいなと思ったものの、npm scriptsのhookがあるから便利なんだろうなと考えるとうーん。。。 となりました