一、背景
故事从日常团队协作开发展开,整个team使用react + antd4搭建前端页面,在开发中我发现antd4.9.*版本的Input.TextArea组件存在一个bug,该bug表现为maxLength属性限制不符合预期,当输入中文字符时,该属性会将与中文对应的预输入拼音字数一同限制,导致汉字输入长度受阻。查阅了github仓库issue及相关changelog发现官方在v4.15.*版本修复了该bug。

遇到这种问题和大多数人一样,我首先想到的就是升级antd到最新版本,于是二话不说一顿操作,升级完后果然问题迎刃而解~
然而问题真的解决了么?事情往往不是预期的那么顺利,本以为一波愉快升级已经完美的解决了问题,不料好景不长一周后小A同学发来问候:“我发现antd v4.15.3版本存在一个bug,upload组件在windows上无法触发beforeUpload钩子,新功能着急走查于是我将antd定了4.9.4版本”。如此噩耗袭来内心自然是千般不适,进退两难之间脑海中浮现出了之前早有耳闻但一直疏于尝试的打补丁大法,二话不说开始操作。
二、给npm包打补丁
1.安装 patch-package
npm i patch-package --save-dev
2.修改npm包
为了避免 v4.15.3 版本之前的其他组件存在未知bug,本次补丁我们基于 4.15.3 版本给 upload 组件打补丁。
打开目标项目代码 node_modules 文件夹,确认是4.15.3版本

打开一个不用的工程,安装 v4.9.4 版本并同样打开antd目录

使用复制大法将我们要修改的upload组件代码从 4.9.4 copy到 4.15.3 ,然后 npm run dev启动项目,测试upload组件的bug是否被修复。
3.生成补丁
经验证效果符合预期,此时cd到根木录下,执行如下命令生成补丁文件:
npx patch-package antd
此时在根目录下会得到如下文件

很好奇.patch文件是个什么东东,打开文件一目了然,其实就是一些git diff记录描述,补丁原理呼之欲出 ——
patch-package会将当前node_modules下的源码与原始源码进行git diff,并在项目根目录下生成一个patch补丁文件。

4.加入版本管理
至此补丁文件已经生成完毕,我们需要将它提交到git中,直接执行常规git操作即可:
git add patches/antd+4.15.3.patch
git commit -m "feat:添加antd补丁"
git push
5.完善npm脚本
当其他同事拉到代码如何应用补丁呢?基于上述操作我们在npm install后执行patch-package命令即可,这个流程可借助npm script实现,在package.json的script中添加如下字段及内容:
{
"postinstall":"patch-package"
}
执行一次完成的「依赖安装 -> 构建发布」,一切符合预期,大功告成~
三、其他方式
那其实想要单纯修改 npm 包方法不止本文介绍的patch-package,对比下其他方法,才能感受到为何patch-package是最优解。
1、单文件修改法
原理是先找到要修改的npm包的文件,先把这个文件拷贝一份到项目目录下,接着修改文件内容并使用
- 拷贝覆盖法
还是用postinstall这个勾子,在这个勾子执行cp 修改过的文件 ./node_modules/包名/原始文件拷贝过去,最终node_modules下的文件就变成了修改后的文件了,应用在本篇antd例子中如下:
"scripts": {
"postinstall": "cp ./patches/upload/* ./node_modules/antd/lib/"
}
即在每次install包后执行用修改后文件覆盖原始文件逻辑。
- 修改引用法
配置一个webpack alias别名,如'原始文件的引用路径': '修改后文件的引用路径',使得最终修改后的文件被引用,如:
resolve: {
alias: {
'antd/upload': path.resolve(__dirname, './patched/upload/*'),
}
}
2、整体copy项目法
将需要修改的包的项目源码整个拷贝下来,进行修改,然后使用
-
直接引用法
直接使用完成的源码,不再通过npm包方式引用。
-
发布私库法
适合一个npm包几个项目在用的场景,可以把修改后的源码发布到私有的npm仓库上,供项目使用,这样多个项目就只需要修改一次源码
3、外部代码修改法
这个方法就是不直接修改 node_modules 的源码,而是利用js特性,在执行时,修改这个包的内部属性,从而达到目的。
简单来说就是利用defineProperty、prototype等特性修改包内的类,举个不恰当的例子,如Vue2.0中使用defineProperty给组件实例做数据劫持和代理。在vue项目中我们也经常在main.js中给Vue根实例通过Vue.prototype.xxx=xxxx挂一些全局属性和方法。
4、patch-package优势
使用上述三种方式虽然能通过一些骚操作解决某些特定场景下的问题,但都无法避免版本升级带来的困扰,如果该npm包升级,可能会导致原先的修改产生错误,所以如果想使用上述三种办法,最好还是要将版本号写死。然而patch-package有如下特性:
-
版本试错
如果你装的包版本和你之前生成的补丁中记录的版本不一样,
npx patch-package会直接报错**ERROR** Failed to apply patch for package xxxx at path,通过提示你可以更方便的定位问题 -
节省空间
使用
git diff来记录补丁比起重写一份源码的方法更节省空间,即安全,又便捷
总结
通过本文介绍,相信你已经对patch-package有了很好的理解,可以在日常开发中优雅的解决鱼和熊掌不可兼得的难题,但补丁虽能避风日也不及新衣保暖,问题出现时最好还是从正规渠道寻求最根本的解决,如给官方提issue并关注版本更新和bug修复情况,以便及时更新或者移除补丁。愿天下补丁都能早日换新衣~
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!