给第三方组件库打补丁

简介: 本文适合对修改组件库源码、修改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就会失效哦~

相关文章
|
Web App开发 安全 Linux
如何安装 Fedy,并使用它来安装常见的第三方软件
如何安装 Fedy,并使用它来安装常见的第三方软件
265 0
|
安全 JavaScript 前端开发
Javascript框架库漏洞验证
Javascript框架库漏洞验证
2780 0
Javascript框架库漏洞验证
|
1月前
|
安全 前端开发 Android开发
我的 Electron 客户端被第三方页面入侵了
公司有个内部项目是用 Electron 来开发的,有个功能需要像浏览器一样加载第三方站点。 本来一切安好,但是某天打开某个站点的链接,导致 整个客户端直接变成了该站点的页面。 这一看就是该站点做了特殊的处理,经排查网页源码后,果然发现了有这么一句代码。
|
4月前
|
JSON 小程序 前端开发
小程序中使用npm安装vant组件实现按需引入减少代码包大小,避免触发用户隐私协议
微信小程序按需引入 vant 组件,自动清除项目中未使用的 vant 组件,减少代码包大小,避免因未使用到的 vant 组件触发隐私协议提交审核时被拒
67 1
小程序中使用npm安装vant组件实现按需引入减少代码包大小,避免触发用户隐私协议
|
2月前
|
缓存 小程序
【微信小程序-原生开发】启动时自动升级更新到最新版本
【微信小程序-原生开发】启动时自动升级更新到最新版本
38 0
|
4月前
|
前端开发 JavaScript API
React 生态系统:路由、状态管理、调试、测试、组件库、文档……
React 生态系统:路由、状态管理、调试、测试、组件库、文档……
86 0
|
4月前
|
前端开发 JavaScript 开发者
探索npm的高级特性:自定义脚本与包的发布与维护
探索npm的高级特性:自定义脚本与包的发布与维护
|
数据采集 数据库连接 API
获取第三方数据四种方式
减少开发人员逻辑处理。api将功能的逻辑在接口内部封装好,不需要开发人员在自行的编写逻辑
|
开发工具 git
从0搭建Vue3组件库(八):使用 release-it 实现自动管理发布组件库
从0搭建Vue3组件库(八):使用 release-it 实现自动管理发布组件库
171 0
|
存储 SQL 安全
typecho新漏洞,强烈建立更新至最新版本!
typecho新漏洞,强烈建立更新至最新版本!
154 0