patch-package 實現原理:如何保存恢復 node_modules 下的代碼改動?
有時候我們需要修改 node_modules 下的一些代碼,但是 node_modules 不會提交到 git 倉庫,改動保存不下來,怎麼辦呢?
這時候可以用 patch-package 這個工具。
比如我對 node_modules 下的 acorn 代碼做了一些修改:
加了一個 a.js 的文件:
在項目目錄下執行 npx patch-package acorn 之後,就會生成這樣一個目錄:
在 patches 目錄下的 xx.patch 文件裏記錄着對這個包的改動。
這個 patches 目錄是可以提交到 git 倉庫的,然後再次把項目拉下來的時候,執行下 npx patch-package 就會應用這次改動。
可以把它配到 postintsll 裏,每次安裝完依賴自動跑。
這樣能保證每次拉取下來的代碼都包含了對 node_modules 的改動。
如何使用我們學會了,那它是怎麼實現的呢?
探究它的實現原理要分爲兩各方面,一個是 patches 文件怎麼生成的,一個是 patches 文件怎麼被應用的。
patches 文件怎麼生成的
看 patches 文件的內容就能看出來這是 git 的 diff:
確實,patch-package 就是依賴 git diff 實現的 patches 文件生成。
首先 patch-package 會創建一個臨時目錄:
然後在這個目錄寫入一個 package.json 文件,dependencies 就是命令行參數指定的包名:
我們去這個目錄看一下:
確實,是有這樣一個 package.json 的。
然後它會在這個目錄下執行 yarn install 或者 npm install(patch-package 現在不支持 pnpm):
之後就進行 git 的 init、add、commit,生成一個基礎的 commit。
然後把現在 node_modules 目錄下的這個被修改過的包複製過去:
之後再 git add,然後執行 git diff,就能拿到改動的 diff:
這不就是 patches 文件的內容麼:
然後寫到 patches 目錄即可
patches 文件的生成還是挺簡單的,就是在臨時目錄下創建了一個基礎 commit,然後把新的內容複製過去,通過 git diff 生成的 patches 內容。
那應用 patches 的內容是怎麼實現的呢?
patches 如何被應用的?
我又對 acorn 目錄下的文件做了些修改,生成的 patches 文件是包含了增刪改的:
patches 文件裏記錄了對哪幾行做了新增,哪幾行做了刪除,哪幾行做了修改。
如果人工應用這個 patches 文件的話,不就是找到對應文件的對應行數,做反向的操作就可以了麼?
沒錯,patch-package 也是這樣實現的,不過是自動進行的:
它讀取 patches 文件之後會進行 parse:
這個 parse 的實現就是對每一行的字符串做判斷,進行不同的處理:
最終能得到一個包含 diff 信息的對象,包含了對什麼文件的哪些行做了什麼修改:
之後對不同的類型做不同的操作就可以了:
這樣就把 patches 文件裏的改動應用到了 node_modules 下的包裏。
總結
當我們需要對 node_modules 下的代碼做改動的時候,可以通過 patch-package xxx 生成 patches 文件,它可以被提交到 git 倉庫,然後再拉下來的代碼就可以通過 patch-package 來應用改動。
實現原理要分爲兩部分來看:
patches 文件的生成是在臨時目錄生成 package.json,下載依賴,生成一個 commit,然後把改動的代碼複製過去,兩者做 gif diff,就可以生成 patches 文件。
patches 文件的應用則是 patch-package 自己實現了它的 parse,拿到對什麼文件的哪些行做什麼修改的信息,之後根據不同做類型做不同的文件操作就可以了。
整體看下來,這個小工具的原理還是挺清晰的,不過 parse patch 文件那部分還是有些麻煩的,當你需要解析 git diff 信息的時候,也可以參考下它的實現。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/D3fx79O1Tn6ygK1_iNEOpA