使用“黑魔法”优雅的修改第三方依赖包

9491f289ed14150a331df3b4fb732e0e.png

背景

Vue项目中使用的element-ui,由于弹窗里表单项太多,一些表单项会在可视范围之外。校验表单时,如果未通过校验的表单项在可视范围外,用户感知不强。所以需要在表单校验未通过时滚动到第一个未通过校验的表单项那里,翻看element-ui文档,发现未提供该API。

起初想到的方案有两种:

  1. 在业务中封装函数,表单校验失败时调用该函数,根据表单校验失败的className,获取第一个校验失败的dom元素,滚动到指定的dom元素位置。但是如果页面存在多个form表单需要做区分,会增加我们的一个工作量,并且不够优雅。

  2. 修改element-ui的源码,增加一个API。但是在平台编译时如果重新执行npm install时代码会被覆盖,并且团队协作时也会遇到这个问题,团队开发中有诸多不便。

后面经过一顿搜索后,发现一个“黑魔法”的解决方案。并且该方案上手简单、便携、且一劳永逸。

黑魔法之patch-package

2a7ed530f921862d347bc02e8e00c3ba.png
patch-package

先看看官方是怎么介绍的

patch-package lets app authors instantly make and keep fixes to npm dependencies. It's a vital band-aid for those of us living on the bleeding edge.

Patches created by patch-package are automatically and gracefully applied when you use npm(>=5) or yarn.

No more waiting around for pull requests to be merged and published. No more forking repos just to fix that one tiny thing preventing your app from working.

总而言之,patch-package给开发者提供了通过打“补丁”的方式,使得重新安装依赖包时能够保留之前对第三方依赖包的修改的一种解决方案。

patch-package的应用场景

想想我们在使用第三方依赖包时如果遇到了bug,通常解决的方式都是绕过这个问题,使用其他方式解决,较为麻烦。或者给作者提个issue或者PR,然后等待作者的修复。等待的时间不可控,如果你不想天天被产品、测试后面追着,是不是就可以借助patch-package自己动手去修复该bug,感觉是不是很棒。并且还可以在第三方依赖包上,根据业务需求扩展能力。

Tip:最好还是扩展一些通用性比较高的能力,如果是比较通用且该能力大多数开发者都有这种诉求的话可以给第三方依赖包提个PR。参与开源项目是不是简单了起来了~(不要在魔改的路上越走越远!!!)

patch-package的使用

Step1:安装

使用npm安装

npm i patch-package

使用yarn安装

yarn add patch-package postinstall-postinstall

为什么要使用yarn安装需要多安装postinstall-postinstall这个依赖,有兴趣可以看官方解释。Why use postinstall-postinstall

Step2:修改package.json文件

package.json的scripts中声明了一系列的npm脚本命令,如下:(参考资料:http://caibaojian.com/npm/misc/scripts.html)

  • prepublish: 在包发布之前运行,也会在npm install安装到本地时运行

  • publish,postpublish: 包被发布之后运行

  • preinstall: 包被安装前运行

  • install,postinstall: 包被安装后运行

  • preuninstall,uninstall: 包被卸载前运行

  • postuninstall: 包被卸载后运行

  • preversion: bump包版本前运行

  • postversion: bump包版本后运行

  • pretest,test,posttest: 通过npm test命令运行

  • prestop,stop,poststop: 通过npm stop命令运行

  • prestart,start,poststart: 通过npm start命令运行

  • prerestart,restart,postrestart: 通过npm restart运行

可以看到依赖包在安装完之后会执行postinstall命令

所以我们在package.json的scripts里面增加:"postinstall": "patch-package"

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

Step3:修改依赖包源码

以element-ui为例:

0481093d345c029852360432e6bdfd45.png
image-20210913202847229

我们在element-uiButton组件上加一个类名button看看

1ef4981a9b611b2ffc9a88d9cc13b267.png
image-20210913203142458

通过控制台查看我们的修改已经生效

Step4:生成补丁

yarn patch-package package-name(修改的包名)
或者
npx patch-package package-name(npm版本 > 5.2)

这里我们执行npx patch-package element-ui命令看看

feiyu@feiyudeMacBook-Pro demo % npx patch-package element-ui
patch-package 6.4.7
patch-package: you have both yarn.lock and package-lock.json
Defaulting to using npm
You can override this setting by passing --use-yarn or deleting
package-lock.json if you don't need it

• Creating temporary folder
• Installing element-ui@2.15.6 with npm
• Diffing your files with clean files
✔ Created file patches/element-ui+2.15.6.patch

💡 element-ui is on GitHub! To draft an issue based on your patch run

    npx patch-package element-ui --create-issue

可以看到patch-package已经为我们创建了一个补丁。

默认会在我们的根目录下创建一个patches文件夹。在patches文件夹下会创建依赖包名+版本号.patch的文件,文件描述了我们修改了什么,第几行,有点像git的提交记录。

86758544009330dba8ffcaeb1f44395a.png
image-20210913203711120

Step5:测试补丁是否有效

  • 手动删除node_modules文件夹,重新执行npm install安装依赖包。可以看到在依赖包安装结束后执行了patch-package命令,之前生成的补丁被应用了。

    > patch-package
    
    patch-package 6.4.7
    Applying patches...
    element-ui@2.15.6 ✔
  • 查看node-modules中之前修改的element-ui修改的地方,查看之前修改的代码是否还存在。如果之前修改的代码还存在,说明补丁文件已经生效了,如果不存在,排查下是否哪个步骤出现了问题。

最后将patches文件夹推送到远端仓库,日后无论是谁拉取代码,安装依赖,我们之前修改的部分都会生效的

注意事项

  1. patch是锁定版本号的,如果升级了版本,patch内容将会失效,最好在package.json能够锁定版本号。

  2. 魔改的同时,也局限了升级的能力,尽量还是去提issue和PR。

最后

patch-package还提供了一些额外的参数,有兴趣的话可以查看官方文档。

参考资料

patch-package-官方:https://github.com/ds300/patch-package

npm-scripts文档:http://caibaojian.com/npm/misc/scripts.html

Why use postinstall-postinstall:https://github.com/ds300/patch-package#why-use-postinstall-postinstall-with-yarn

- END -

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: CSS的counter计数器是一种非常有用的技巧,用于在网页中实现自动计数和编号的功能。通过使用计数器,我们可以方便地对网页元素进行编号,比如列表、章节标题等。 首先,我们需要定义一个计数器。可以使用counter-reset属性来定义计数器并初始化它的值。例如,如果我们想要创建一个从1开始的计数器,可以这样写: ``` body { counter-reset: counterName 1; } ``` 这里的counterName是我们给计数器起的名字,可以自定义。1表示计数器的初始值。 接下来,我们可以在需要计数的元素中使用counter-increment属性来递增计数器的值。例如,如果我们想要在每个列表项前显示它的编号,可以这样写: ``` ul li:before { counter-increment: counterName; content: counter(counterName) ". "; } ``` 这里的counter-increment用于递增计数器的值,content用于显示计数器的值。我们使用了counter()函数来获取计数器的值,并在后面加上了一些文字(比如点号和空格)来实现编号的显示效果。 我们还可以根据需要在不同的元素中使用不同的计数器。只需要给不同的计数器起不同的名字,并在对应的元素中使用相应的计数器名字即可。 总的来说,CSS的counter计数器是一种非常灵活和强大的技巧,可以用于各种需要进行自动计数和编号的场景。通过定义计数器、递增计数器和使用counter()函数来获取计数器的值,我们可以轻松地实现网页元素的编号效果。 ### 回答2: 计数器(counter)是CSS中的一个功能强大的特性,可以用于在HTML文档中创建计数器,然后在样式规则中使用这些计数器来生成序号或标记。以下是使用计数器(counter)的一些技巧: 1. 创建一个计数器: 使用 `counter-reset` 属性可以创建一个计数器,并可以为其设定一个初始值。例如,可以创建一个以1为初始值的计数器: ```css .container { counter-reset: my-counter 1; } ``` 2. 更新计数器的值: 使用 `counter-increment` 属性可以更新计数器的值。可以在选择器中的任何位置使用这个属性。例如,每当 `li` 元素出现时,可以将计数器的值增加1: ```css li { counter-increment: my-counter; } ``` 3. 在内容中引用计数器的值: 使用 `content` 属性可以在样式规则中引用计数器的值,并将其插入到生成的内容中。可以使用计数器的名称作为 `content` 的值。例如,将计数器的值作为新的内容插入到列表项前面: ```css li::before { content: counter(my-counter) ". "; } ``` 4. 在不同的元素中使用多个计数器: 可以在同一个文档中使用多个不同的计数器,并为它们设定不同的初始值。这样可以为不同的元素生成不同的序号或标记。例如,可以为不同的标题元素创建不同的计数器: ```css h1 { counter-reset: h1-counter 1; } h2 { counter-reset: h2-counter 1; } ``` 5. 控制计数器的显示方式: 使用 `counter()` 函数可以对计数器的显示方式进行自定义。可以指定计数器的名称,以及任何显示格式。例如,可以将计数器的值格式化为罗马数字: ```css .container::after { content: counter(my-counter, upper-roman); } ``` 总结而言,计数器(counter)是CSS中一项非常实用的黑魔法技巧。通过创建、更新和引用计数器的值,可以在样式规则中生成序号或标记,并且可以通过自定义显示格式来控制计数器的外观。 ### 回答3: CSS中的计数器(counter)是一种非常强大的工具,可以用来计数、标记和显示元素的编号或序号。它可以通过一些技巧来实现各种有趣的效果。 首先,使用counter-reset属性来定义计数器并将其重置为指定的起始值。例如,可以使用"counter-reset: section 0;"来将名为"section"的计数器重置为0。 然后,可以通过counter-increment属性来递增计数器的值。例如,使用"counter-increment: section;"来递增名为"section"的计数器的值。 接下来,在需要显示计数器的地方,可以使用content属性来显示计数器的值。例如,使用"content: counter(section);"来在伪元素的内容中显示名为"section"的计数器的值。 可以进一步利用计数器,实现复杂的效果。例如,可以使用:before伪元素和content属性来在每个元素前面显示计数器的值,从而实现自动标号的效果。例如,使用"content: counter(section) '. ';"来在每个元素前面显示名为"section"的计数器的值,并跟随一个点号。 此外,还可以使用counter()函数获取和修改计数器的当前值。例如,可以使用"counter(section)"来获取名为"section"的计数器的当前值,并将其用作其他属性的值。 总的来说,计数器是CSS中非常强大且灵活的工具,可以用来实现各种复杂的效果。熟练掌握计数器的使用技巧,可以让我们的CSS代码更加精细和有趣。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值