几种修改前端第三方库(bug)的方法


1.在github上提issue

通常第三方库都有自己的github仓库地址或者官网,如果有github仓库的话就可以在github上提issue,要注意的是一定要按照仓库作者规定的格式提issue,写明bug复现过程,否则issue可能会被忽略。

这种方法理论上是最好的,但是也有一些缺点:

  • 仓库作者可能不维护了,那么issue将不会被解决
  • 仓库作者不认同观点,可能会拒绝所提的issue
  • 仓库作者接受所提的issue,但认为其优先级低,可能需要很长时间才会解决

2.fork代码自己修改

如果急需解决bug的话,可以尝试自己把原仓库fork下来进行修改,并且将代码发布到npm仓库中,供项目使用。这种方法的缺点有:

  • 增加维护成本,需要和原仓库保持同步,否则会丢失更新
  • 后期可能会和原仓库出现难以合并的分歧
  • 注意合法性问题,可能需要原作者授权

综上,如果原仓库一直在更新的话,需要考虑原仓库和自己仓库的代码同步问题,因此这种方法更适合在原仓库不再维护的情况下使用。

此外还可以给仓库作者提PR,这样就不用担心后续维护的问题了,也是一种比较好的方式,即满足了自己的需求还为开源库做了贡献,但前提是作者接受了PR

3.使用pack-package打补丁

在不修改源代码的情况下,也可以通过直接修改其打包后的代码来实现所需功能,步骤如下:

安装pack-package

npm i patch-package

修改代码

node_modules中找到对应模块的位置,以element-plus为例,假设要对Button组件的点击事件进行修改,找到Button组件以及代码中相应位置,如图所示,添加代码console.log('click')。代码修改后的预期结果是所有用了Button组件的地方,在点击按钮时都会在控制台输出click

验证代码

模版中使用el-button组件:

<template>
  <div>
    <el-button>Default</el-button>
  </div>
</template>

如下图所示代码中并没有主动监听el-button的click事件,但是每次点击时都会在控制台输出"click"

注:如果使用了vite,要注意在重新运行前清除缓存,否则可能会出现代码不生效的问题。

保存修改的代码

为了便于代码的分发,需要把在element-ui中修改的代码保存下来,通过执行命令npx patch-package package-name会生成一个.patch文件,里面包含了修改前后的diff信息。

其中内容为:

diff --git a/node_modules/element-plus/es/components/button/src/use-button.mjs b/node_modules/element-plus/es/components/button/src/use-button.mjs
index 884214f..59c9c6c 100644
--- a/node_modules/element-plus/es/components/button/src/use-button.mjs
+++ b/node_modules/element-plus/es/components/button/src/use-button.mjs
@@ -52,6 +52,7 @@ const useButton = (props, emit) => {
     return false;
   });
   const handleClick = (evt) => {
+    console.log('click')
     if (_disabled.value || props.loading) {
       evt.stopPropagation();
       return;</font>

至此,只要执行patch-package命令即可将patch中的代码并入到node_modules对应文件中。为简化此过程,通常在package.jsonscripts对象中加入"postinstall": "patch-package"配置,这样每当执行npm install之后,都会自动执行patch-package命令。

适用场景

和第二种方法的适用场景类似,但更加适用于修改一些较小的bug,因为node_modules中通常是打包后的代码,特别是经过混淆和压缩的代码,修改难度相对较高。另外打补丁的方法也不需要去另外维护仓库。需要注意的是用这种方法修改,需要锁定包的版本,如果后期需要升级包的话,补丁也需要看实际情况去做相应修改。

4.pnpm patch打补丁

pack-package类似。

使用命令pnpm patch package-name,还是以element plus为例,命令为pnpm patch element-plus,执行命令后会将对应npm包复制到一个叫.pnpm_patches的目录中,如下图所示。

然后就可以在这个新生成的目录中编辑代码,依然在相同位置添加代码console.log('click')。编辑完成后,执行上图中绿色的提交修改的代码。

此时package.json中自动多了代码:

"pnpm": {
  "patchedDependencies": {
    "element-plus": "patches/element-plus.patch"
  }
}

同时目录中也多了patches文件夹,以及element-plus.patch这个补丁文件,里面也是修改前后的diff信息。

最后删除node_modules文件夹,重新安装依赖,查看修改后的代码是否被添加进来。

这种方法的适用场景和使用pack-package是类似的。

5.动态修改代码(Vue)

由于在vue中通过ref可以拿到所使用组件的实例对象,所以理论上我们可以直接修改这个实例对象来达到一些目的。以element-plusel-cascader级联组件为例,查看实例对象:

里面有一个cascaderPanelRef属性,el-cascader是基于cascaderPanel的,它包括了级连组件的核心功能。cascaderPanelRef中有:

注意到里面有一个handleKeyDown的方法,这个方法的详细信息并没有在官方文档中所体现,根据其名称,猜测会对键盘方向键的事件进行处理。尝试对其进行修改:

onMounted(() => {
  let value = refCascade.value
  nextTick(() => {
    let cascaderPanelRef = value.cascaderPanelRef
    let old = cascaderPanelRef.handleKeyDown

    cascaderPanelRef.handleKeyDown = function (...args) {
      old.apply(cascaderPanelRef, args)
      console.log('keydown')
    }
  })
})

如上述代码所示,在保持原有功能的基础上,每当触发keydown事件时,还会在控制台打印keydown

由于handleKeyDowncascaderPanelRef对象自身的方法,并非是从原型链上继承的,因此上面所做的修改只在当前组件实例生效,其它同样的组件是不受任何影响的。

注:vue2中的ref可拿到完整的组件实例对象,而vue3中只能拿到组件主动暴露出来的属性或方法,修改受限,这种方法在vue2中更能发挥作用。

总结

在有条件的情况下,尽可能选择第一种方案,可以免去后续维护代码的工作。否则要修改的代码较多的话可以选择第二种方案,同时也可以给作者提PR,若作者接受的话也可以免去后续代码维护的工作。其他情况酌情选择第3、4、5种方案。

https://www.cnblogs.com/smileZAZ/p/18310045

https://juejin.cn/post/7356534347509497919

声明:Hello World|版权所有,违者必究|如未注明,均为原创|本网站采用BY-NC-SA协议进行授权

转载:转载请注明原文链接 - 几种修改前端第三方库(bug)的方法


Carpe Diem and Do what I like