6

Node: 使用patch-package或其他方式给npm包打补丁

 1 year ago
source link: https://lianpf.github.io/posts/develop-diary/38.npm-patch-package/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

日常团队协作过程中,由于现状不得不使用相对滞后版本的依赖包,但又期望使用新版本的某些功能…


通常情况下,遇到需要支持的底层功能,开发人员直接升级依赖包版本即可,但总有意外。比如:

  • 日常团队协作开发不同于个人独立开发,因为历史原因,不得不使用某个依赖包相对滞后的某个版本,但又需要新版本依赖包的某些功能。
  • 新版本包存在未知的bug,但你的团队期望使用新版本中的某些已验证功能。
  • 依赖包已经更新到最新版本,但存在官方未修复的bug

此时,往常一波愉快的依赖包版本升级已经不能解决问题了。我们不得不祭出**“打补丁大法”**。


二、patch-package打补丁

1.生成补丁

I. 安装 patch-package

# 安装 patch-package
$ npm i patch-package --save-dev

II. 修改npm包 以我本次需求为例,我当前需要打补丁的包是@vant/cli 5.1.0,无论是新老版本都没有支持我需要的功能。所以,

  • 打开目标项目工程(A)/node_modules文件夹,确认版本是5.1.0
  • 稳妥起见,打开一个废弃的前端工程(B),安装@vant/cli 5.1.0(我这里偷懒使用的项目工程),打开node_modules/@vant/cli目录
    • 场景1: 将你期望的新版本对应功能,复制粘贴到当前工程(B)对应node_modules/xxx目录文件内
    • 场景2: 自行修复bug或diy你期望的功能,到当前工程(B)node_modules/xxx对应目录文件内
  • npm run dev启动工程(B),测试功能是否满足期望。

III. 生成补丁文件
功能符合预期,此时cd到工程(B)根木录下,执行如下命令生成补丁文件:

$ npx patch-package @vant/cli

终端可看到执行记录如下:

$ npx patch-package @vant/cli
patch-package 6.4.7
• Creating temporary folder
• Installing @vant/[email protected] with npm
• Diffing your files with clean files
✔ Created file patches/@vant+cli+5.1.0.patch

💡 @vant/cli is on GitHub! To draft an issue based on your patch run

    npx patch-package @vant/cli --create-issue

最终在工程(B)根目录下,生成工程(B)/patches/@vant+cli+5.1.0.patch补丁文件,将它提交到git中。

补丁原理也不复杂,其实就是一些git diff记录描述:
patch-package会将当前node_modules下的源码与原始源码进行git diff,并在项目根目录下生成一个patch补丁文件。以我当前的为例:

diff --git a/node_modules/@vant/cli/site/index.html b/node_modules/@vant/cli/site/index.html
index 5764eed..e32fb9e 100644
--- a/node_modules/@vant/cli/site/index.html
+++ b/node_modules/@vant/cli/site/index.html
@@ -33,5 +33,8 @@
   <body>
     <div id="app"></div>
     <script type="module" src="/desktop/main.js"></script>
+    <script>
+      window.localStorage.setItem("vantTheme", "light")
+    </script>
   </body>
 </html>
diff --git a/node_modules/@vant/cli/site/mobile.html b/node_modules/@vant/cli/site/mobile.html
index e5ff77b..084a028 100644
--- a/node_modules/@vant/cli/site/mobile.html
+++ b/node_modules/@vant/cli/site/mobile.html
@@ -42,5 +42,8 @@
   <body>
     <div id="app"></div>
     <script type="module" src="/mobile/main.js"></script>
+    <script>
+      window.localStorage.setItem("vantTheme", "light")
+    </script>
   </body>
 </html>

2.执行补丁

基于以上操作,切回到目标项目工程(A),在package.json中添加命令如下:

{
  "scripts": {
    "postinstall":"patch-package" // 会在包安装完成后执行
  }
}

执行依赖安装 -> 构建发布,符合预期。

$ npm i
install 依赖包
...

> @zto/[email protected] patch
> patch-package
patch-package 6.4.7
Applying patches...
@vant/[email protected] ✔
...
patch-package finished.

三、其他方式

想要单纯修改npm包还有其他方式。

1.对于单文件

  • 拷贝覆盖法
  • 修改引用法

利用postinstall勾子,执行cp 修改过的文件 ./node_modules/包名/原始文件,最终node_modules下的文件被覆盖成修改后的文件:

{
  "scripts": {
    // 即每次install包后用修改后文件覆盖原始文件
    "postinstall": "cp ./patches/vant-cli/* ./node_modules/vant/cli/site"
  }
}

配置一个webpack alias别名,如**‘原始文件的引用路径’: ‘修改后文件的引用路径’**,使得最终修改后的文件被引用,如:

// vite 原理类似
resolve: {
      alias: {
          'antd/upload': path.resolve(__dirname, './patched/upload/*'),
      }
  }

2.多个文件/整体项目

  • 直接使用完成的源码,不再通过npm包方式引用
  • 修改后的源码,发布到私有的npm仓库上,供项目使用

  • patch-package优势: 使用git diff来记录补丁,比重写一份源码的方法更节省空间、安全和便捷
  • patch-package可在日常开发中优雅的解决鱼和熊掌不可兼得的难题。但问题出现时,最好还是从官方渠道寻求解决方案,如提issue并关注版本更新和bug修复情况,以便及时更新或者移除补丁。

最后, 希望大家早日实现:成为编程高手的伟大梦想!
欢迎交流~

微信公众号

本文版权归原作者曜灵所有!未经允许,严禁转载!对非法转载者, 原作者保留采用法律手段追究的权利!
若需转载,请联系微信公众号:连先生有猫病,可获取作者联系方式!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK