给第三方组件库打补丁

简介: 本文适合对修改组件库源码、修改npm包,生成补丁包感兴趣的小伙伴阅读~

一、前言


广东靓仔之前修改过element的代码,然后固定本地版本。隔了这么久,广东靓仔前阵子在看修改npm包方面的内容发现一个有趣的,且听广东靓仔徐徐道来。

之前为什么会需要修改element的代码呢?原因很简单,因为组件库不满足业务需要。

同理啦,如果是Ant Design不满足我们也是可以修改的。往大的来说,所有的npm包我们其实都是可以修改的。

那么问题来了,如何改?业界其实是有很多种方案,我们一一来看。


二、一个简单的场景


修改antd组件库button

咋们先来个简单的场景:组件库里面的button不满足我们了,需要改成span(夸张点)。


第一步:找到node_modules里面的antd

路径:node_modules -> antd -> es -> button -> button.js


这里稍微补充下:

1. CommonJS模块是对象,是运行时加载,运行时才把模块挂载在exports之上。

2.ES Module不是对象,是编译时加载,使用export指定导出,再通过import引入。

image.png


我们把button修改为span即可

- var buttonNode = /*#__PURE__*/React.createElement("button", _extends({}, rest, {
  + var buttonNode = /*#__PURE__*/React.createElement("span", _extends({}, rest, {
    type: htmlType,
    className: classes,
    onClick: handleClick,
    ref: buttonRef
  }), iconNode, kids)


第二步:修改npm包,常见有4种,这里罗列对比下,推荐方法4


  • 方法一:单文件修改法

使用postinstall这个勾子,执行cp 修改过的文件 ./node_modules/antd/button.js拷贝过去,最终node_modules下的文件就变成了修改后的文件了,代码如下:

"scripts": {
    "postinstall": "cp ./patches/upload/* ./node_modules/antd/lib/"
}

在每次install包后执行用修改后文件覆盖原始文件逻辑。


  • 方法二:整体copy项目法

将需要修改的包的项目源码整个拷贝下来,进行修改,然后使用

  • 直接引用法
    直接使用完成的源码,不再通过npm包方式引用。
  • 发布私库法
    适合一个npm包几个项目在用的场景,可以把修改后的源码发布到私有的npm仓库上,供项目使用,这样多个项目就只需要修改一次源码

  • 方法三:外部代码修改法

这个方法就是不直接修改 node_modules 的源码,而是利用js特性,在执行时,修改这个包的内部属性。

比如利用definePropertyprototype等特性修改包内的类,举个不恰当的例子,如Vue2.0中使用defineProperty给组件实例做数据劫持和代理。在vue项目中我们也经常在main.js中给Vue根实例通过Vue.prototype.xxx=xxxx挂一些全局属性和方法。


  • 方法四:patch-package

patch-package有如下特性:

  • 版本试错
    如果你装的包版本和你之前生成的补丁中记录的版本不一样,npx patch-package会直接报错**ERROR** Failed to apply patch for package xxxx at path,通过提示你可以更方便的定位问题
  • 节省空间
    使用git diff来记录补丁比起重写一份源码的方法更节省空间,即安全又便捷


综合上面4种,最后我们采用第四种来修改npm包。step 1: 安装

yarn add antd patch-package postinstall-postinstall -D


setp 2: 在package.json文件script中添加脚本命令

"scripts": {
+  "postinstall": "patch-package"
 }


step 3: yarn patch-package antd打补丁最后会生成一个antd+4.17.5.patch的包

通过查看这个包的代码,我们发现是通过diff --git来对比不同的。

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

image.png


把这个补丁包上传到仓库后,其他人安装依赖的时候,node_module文件对应的文件也保留了修改。

拓展一下,其他组件库,也同样可以这样子来修改,比如@alifd/next。

image.png


三、一个复杂的场景


修改antd组件库table

image.png

广东靓仔随便弄了个图,可以看出来就是在table里每条信息插入一行其他信息。这种需求确实很常见,靓仔遇到过很多这种需求。


按照前面第一个例子,思路差不多。


我们都知道antd的table内核使用的是rc-table这个库,因此我们修改node_modules里面的rc-table源代码即可。


路径:node_modules -> rc-table-> es -> Body -> BodyRow.js


在表格每行内容前插入一行信息,所以我们需要自定义一个变量来初始化插入的内容,这里不写具体代码,讲思路。


第一步: 在body的行增加一个变量"变量名"用来插入我们需要的渲染内容

image.png


第二步: 参考rc-table本身插入节点的expandRowNode,编写我们需要插入的内容

image.png


参考代码:

+  var 变量名;
+
+  if (typeof 变量名 === 'function') {
+   ......
+ }


第三步: 在return那里把我们新加的“变量”返回

-  return /*#__PURE__*/React.createElement(React.Fragment, null, baseRowNode, expandRowNode, nestRowNode);
+  return /*#__PURE__*/React.createElement(React.Fragment, null, 变量, baseRowNode, expandRowNode, nestRowNode);


最后:Table.js里面把useMemo的依赖加上我们新加的变量


路径:node_modules -> rc-table-> es -> Table.js

image.png


在BodyContextValue把我们加上“变量”

var BodyContextValue = React.useMemo(function () {
     ...
-  }, [columnContext, mergedTableLayout, rowClassName, expandedRowClassName, componentWidth, fixHeader, fixColumn, horizonScroll, mergedExpandIcon, expandableType, expandRowByClick, expandedRowRender, onTriggerExpand, expandIconColumnIndex, indentSize]);
+  }, [columnContext, mergedTableLayout, rowClassName, expandedRowClassName, componentWidth, fixHeader, fixColumn, horizonScroll, mergedExpandIcon, expandableType, expandRowByClick, expandedRowRender, 变量, onTriggerExpand, expandIconColumnIndex, indentSize]);


这个array 控制useMemo重新执⾏行的数组,array改变时才会 重新执行useMemo。也就是当依赖对应的值发生变化时,才会重新计算。


生成补丁包的方法跟上面那个例子是一样的,这里就不重复了。


四、最后


补丁虽然能解决一些问题,但是这其实不是很好的方案。最好呢是用官方提供的升级版本来解决问题。

最后需要注意一下,当我们升级了我们的版本后,这个patch就会失效哦~

相关文章
|
存储 JSON 数据库
vue3中实现文件上传---通过element-plus的upload组件
vue3中实现文件上传---通过element-plus的upload组件
|
计算机视觉
教你如何玩转Modelscope (一、图片编辑与描述生成)
本文通过一个有趣的图片处理例子,教你如何利用modelscope强大且多样的模型能力去解锁你专属的图片编辑能力。
3445 1
教你如何玩转Modelscope (一、图片编辑与描述生成)
|
JavaScript API 开发者
vue自定义Hooks函数使用和封装思想
【8月更文挑战第8天】vue自定义Hooks函数使用和封装思想
456 1
|
算法 开发工具 git
【git 实用指南】git 增加 本地代码 git add 相关命令和复杂情况需求
【git 实用指南】git 增加 本地代码 git add 相关命令和复杂情况需求
1451 0
|
12月前
|
机器学习/深度学习 数据挖掘 Serverless
手把手教你全面评估机器学习模型性能:从选择正确评价指标到使用Python与Scikit-learn进行实战演练的详细指南
【10月更文挑战第10天】评估机器学习模型性能是开发流程的关键,涉及准确性、可解释性、运行速度等多方面考量。不同任务(如分类、回归)采用不同评价指标,如准确率、F1分数、MSE等。示例代码展示了使用Scikit-learn库评估逻辑回归模型的过程,包括数据准备、模型训练、性能评估及交叉验证。
549 1
|
小程序 测试技术 API
开发字节抖音小程序踩坑记
用uni-app开发多端应用,之前打包的微x小程序好好的,打包成字节的就各种兼容问题,UI框架用的uView的1.x版本,也是各种兼容问题
|
SQL IDE 开发工具
好用的MybatisX插件~
好用的MybatisX插件~
496 0
|
Java 应用服务中间件 Apache
Spring Boot几种启动问题的解决方案
  使用Spring Boot以来,遇到和解决过好几次不同的项目启动问题,大多数事故起于错误的配置和依赖。因此,本文用于汇总这些问题,以及提供相应的解决方案,帮助大家更快的定位和排除故障。
2994 0
|
JavaScript
element-plus vue3 图片上传
element-plus是一款基于Vue 3的UI组件库,它提供了一系列常用的UI组件以及丰富的特色功能。其中包括图片上传,可以通过el-upload组件实现。下面是基于element-plus vue3的图片上传例子:
803 0
|
关系型数据库 MySQL Linux
windows系统中docker部署mysql后,使用navicate链接
windows系统中docker部署mysql后,使用navicate链接
500 0