修改第三方npm包
文章目录
- 一、前言
- 二、补丁方案
- 2.1、`patch-package`
- 2.2、`pnpm patch`
- 三、换日方案
- 四、总结
- 五、最后
一、前言
在开发过程中,发现某个npm包有Bug,应该怎么办?可以试试下面这2种方案:
- 代码量少,可以直接修改
npm包代码的,考虑补丁方案。- 代码量多,或者
npm包代码是压缩混淆过的,不具备修改条件。修改源码后,再修改包名,重新发布,在应用代码中更换引用。为叙文方便,我将这种方案命名为换日方案(偷天换日,李代桃僵)。
二、补丁方案
2.1、patch-package
patch-package是一个用于修复第三方依赖包的工具,使用方式非常简单。
它支持
npm和yarn v1,如果是yarn v2+或者pnpm,则使用自带的patch方案(下文会介绍pnpm方案)。
安装:
$ npm i patch-package
$ yarn add patch-package postinstall-postinstall
如果只是前端使用,可以添加
--dev或-D参数。如果是后端使用,为保障生产模式(会去除devDendencies依赖)也能正常使用,就不要加了。
在node_modules中找到你要修改的npm包,修改内容后,就可以运行patch-package创建patch文件了。
$ npx patch-package package-name # 使用npm
$ yarn patch-package package-name # 使用yarn
运行后会在项目根目录下创建一个patches文件夹,并生成一个名为package-name+version.patch的文件。将该patch文件提交至版本控制中,即可在之后应用该补丁了。
以我修改的verdaccio为例,会生成一个verdaccio+4.4.0.patch的文件,内容大致如下:
diff --git a/node_modules/verdaccio/build/index.js b/node_modules/verdaccio/build/index.js
index 3a79eaa..d00974b 100644
--- a/node_modules/verdaccio/build/index.js
+++ b/node_modules/verdaccio/build/index.js
@@ -5,6 +5,8 @@ Object.defineProperty(exports, "__esModule", {});exports.default = void 0;+console.log('---------------')
+var _bootstrap = require("./lib/bootstrap");
完成上述操作后,最后在package.json的scripts中加入"postinstall": "patch-package"。
"scripts": {"postinstall": "patch-package"
}
这样当其他同事拉下代码,运行npm install或是yarn install命令时,便会自动为依赖包打上我们的补丁了。
简单来说,这个方案的原理就是记录补丁的代码与位置,利用
npm的hook(postinstall会在npm install后触发),在安装完依赖以后,触发相应的脚本,将补丁覆盖到node_modules对应的包里。当然,补丁是对应具体版本的,需要锁定版本号。这样的缺点是如果要升级的话,还得重新来一遍,不过不是有
Bug或性能问题,通常不必追求新的版本。
2.2、pnpm patch
pnpm的patch自称灵感来自yarn的类似命令。由于yarn v2可能走了邪路,我们就不介绍了。
首先,执行pnpm patch <pkg name>@<version>。该命令会将指定的软件包提取到一个可以随意编辑的临时目录中。
完成修改后, 运行pnpm patch-commit <path>(是之前提取的临时目录,这个临时目录会长到你根本记不住,不过不用担心,命令行里会有完备的提示) 以生成一个补丁文件,并提供patchedDependencies 字段注册到你的项目中。
比如,我想修改一个is-even的包:
pnpm patch is-even
You can now edit the following folder: /private/var/folders/sq/0jfgh1js6cs8_31df82hx3jw0000gn/T/29ba74c7c7ffd7aa157831c6436d3738Once you're done with your changes, run "pnpm patch-commit /private/var/folders/sq/0jfgh1js6cs8_31df82hx3jw0000gn/T/29ba74c7c7ffd7aa157831c6436d3738"
按照提示,打开这个文件夹,加一行代码:

执行上面控制台的提示:
pnpm patch-commit /private/var/folders/sq/0jfgh1js6cs8_31df82hx3jw0000gn/T/e103de90617a18eee7942d1df35a2c48
Packages: -1
-
Progress: resolved 5, reused 6, downloaded 0, added 1, done
这时你会发现package.json中多了一段内容:
"pnpm": {"patchedDependencies": {"is-even@1.0.0": "patches/is-even@1.0.0.patch"}
}
根目录下,也多了个文件夹patches,打开以后,你就能找到添加的代码:

打开node_modules/is-even/index.js,可以看到已经多了我们添加的代码:

删除node_modules,重新pnpm i安装依赖,仍然与现在一样,这就代表成功了。
整个流程下来,我们看得出来相比于patch-package,要稍微复杂点儿,但也是可以接受的。
注意:
patches目录是一定得提交到git的。
三、换日方案
如果要修改的代码较多,或者不具备修改条件,这时就需要修改源码。到GitHub上找到npm包的源码,Fork该项目,修改代码后,再修改包名,重新发布,比如你要修改的包是lodash,可以修改为awesome-lodash,在应用代码中更换引用。
本来这个方案没什么好说的,但有一种情况,如果你修改的是个底层包,也就是说并不是你的应用代码中直接引用的,而是你引用的npm包A所依赖的,甚至可能同时被包B依赖的,这时就比较尴尬了,你不可能再去修改A和B的源码,那就太不值当了。
pnpm提供了一种别名(Aliases)的能力。
假设你发布了一个名为awesome-lodash的新包,并使用lodash作为别名来安装它:
$ pnpm add lodash@npm:awesome-lodash
不需要更改代码,所有的lodash引用都被解析到了awesome-lodash。就这么简单,上面说的问题就解决了。
再说点儿题外话,有时你会想要在项目中使用一个包的两个不同版本,很简单:
$ pnpm add lodash1@npm:lodash@1
$ pnpm add lodash2@npm:lodash@2
现在,您可以通过 require('lodash1') 引入第一个版本的 lodash 并通过 require('lodash2') 引入第二个。
与pnpm的钩子结合使用功能会更加强大,比如你想将node_modules里所有的lodash引用也替换为awesome-lodash,你可以用下面的.pnpmfile.cjs 轻松实现:
function readPackage(pkg) {if (pkg.dependencies && pkg.dependencies.lodash) {pkg.dependencies.lodash = 'npm:awesome-lodash@^1.0.0'}return pkg
}module.exports = {hooks: {readPackage}
}
四、总结
在开发过程中发现npm包的Bug,首先向原作者提交issue或Fork代码修改后提交合并请求。但遇到不活跃或拒绝修改的情况,项目等待时间会很长。这时可以使用补丁方案或换日方案进行解决。
补丁方案中,如果是npm或yarn v1,可以使用patch-package工具包处理;如果是yarn v2或pnpm,可以使用各自的patch命令。
换日方案,则是修改源码,发布新的npm包后,利用pnpm的别名功能,将所有依赖原npm包的地方,全部替换为新的包。
这种场景在日常开发中还是比较常见的,这里为大家提供一种思路。当然,如果真是个Bug,别忘了提issue或PR,为开源贡献自己的一份力量,在与作者的沟通交流中,相信你也能受益匪浅。
五、最后
本人每篇文章都是一字一句码出来,希望对大家有所帮助,多提提意见。顺手来个三连击,点赞👍收藏💖关注✨,一起加油☕
相关文章:
修改第三方npm包
文章目录 一、前言二、补丁方案2.1、patch-package2.2、pnpm patch 三、换日方案四、总结五、最后 一、前言 在开发过程中,发现某个npm包有Bug,应该怎么办?可以试试下面这2种方案: 代码量少,可以直接修改npm包代码的&…...
Redis性能优化:关键配置和最佳实践
大家好,我是升仔 Redis作为一个高性能的键值存储系统,在现代应用架构中扮演着至关重要的角色。性能优化是Redis部署与维护中的一个关键环节。本文将从关键配置、持久化配置、实践场景和异常处理配置等方面,详细介绍如何优化Redis的性能。 关…...
华为数通方向HCIP-DataCom H12-831题库(多选题:241-249)
第241题 (NEW) 以下哪些操作可能会影响客户网络的正常运行? A、从设备上下载日志 B、软件升级 C、路由协议配置变更 D、debug核心交换机上转发的所有IP报文 答案:ABCD 解析: 第242题 对于防火墙的默认安全区 Trust 和 Untrust 的说法,正确的有 A、从 Trust 区域访问 Untr…...
typeorm联表查询:副表json格式放到主表字段下或多个副表字段并列主表字段
实体类字段不做映射,typeorm实现联查查询 1、副表json格式放到主表字段下 //goods表和member表联表,关系goods.id member.uid,member表数据json对象格式放到主表userInfo下 //leftJoinAndMapOne配合getMany实现 const builder await getCo…...
Flume采集日志存储到HDFS
1 日志服务器上配置Flume,采集本地日志文件,发送到172.19.115.96 的flume上进行聚合,如日志服务器有多组,则在多台服务器上配置相同的配置 # Name the components on this agent a1.sources r1 a1.sinks k1 a1.channels c1# Describe/con…...
redis—String字符串
目录 前言 1.字符串数据类型 2.常见命令 3.典型应用场景 前言 字符串类型是Redis最基础的数据类型,关于字符串需要特别注意: 1)首先Redis中所有的键的类型都是字符串类型,而且其他几种数据结构也都是在字符串类似基础.上构建的,例如列表…...
三相电机转差率为负值的情形
1.电机开始发电的特征 注意,电机因为有输入频率对原始旋转磁场的影响,在正常工作时,应该处于稳态,因为旋转磁场决定了这个系统的运转方向和运转的大致频率区间。它会处于力矩平衡态。但是,如果,此时电机处…...
关于Dark Frost 僵尸网络对游戏行业进行DDoS攻击的动态情报
一、基本内容 近期,一种名为Dark Frost 的新型僵尸网络被发现正在对游戏行业发起分布式拒绝服务攻击(DDoS)。目标包括游戏公司、游戏服务器托管提供商、在线流媒体甚至和网络信息安全攻击者直接交互的其他游戏社区成员。截至2023年2月,僵尸网…...
MongoDB数据库本地部署并结合内网穿透实现navicat公网访问
文章目录 前言1. 安装数据库2. 内网穿透2.1 安装cpolar内网穿透2.2 创建隧道映射2.3 测试随机公网地址远程连接 3. 配置固定TCP端口地址3.1 保留一个固定的公网TCP端口地址3.2 配置固定公网TCP端口地址3.3 测试固定地址公网远程访问 前言 MongoDB是一个基于分布式文件存储的数…...
前端学习笔记
文章目录 1、学习路线2、token的安全储存方案3、跨域4、相关的学习链接 前言:最近在学习前端补齐我的软件技能树,最近简单总结一下 1、学习路线 基本:vue3、ts(js)、 vite、eslint、css(动画、布局) 依赖包:vue-router、vue-i18…...
Vue实现响应式布局
前提准备:响应式布局有两种方法,看自己想要哪种。 方法一:百分比 用百分比去写元素的宽度,然后让子元素撑起父元素的高度 .parent {width: 50%; }.child {width:100%;height:100px; } 方法二:vh、vw vw、vh是基于视…...
linux:下载、网络请求、端口
一:ping命令 可以通过ping命令,检查指定的网络服务器是否是可联通状态 语法: ping [-c num] ip或主机名 1、选项:-c,检查的次数,不使用-c选项,将无限次数持续检查 2、参数:ip或主机名,被检查的服务器的…...
182.【2023年华为OD机试真题(C卷)】敏感字段加密(字符串的分割、替换和拼接实现JavaPythonC++JS)
请到本专栏顶置查阅最新的华为OD机试宝典 点击跳转到本专栏-算法之翼:华为OD机试 🚀你的旅程将在这里启航!本专栏所有题目均包含优质解题思路,高质量解题代码,详细代码讲解,助你深入学习,深度掌握! 文章目录 【2023年华为OD机试真题(C卷)】敏感字段加密(字符串…...
新版IDEA中Git的使用(三)
说明:前面介绍了在新版IDEA中Git的基本操作、分支操作,本文介绍一下在新版IDEA中,如何回滚代码; 分以下三个阶段来介绍: 未Commit的文件; 已经Commit,但未push的文件; 已经push的…...
node - koa 获取 Content-Type: text/plain 的数据
目录 1,Content-Type2,koa 获取请求的数据 1,Content-Type Content-Type HTTP 标头用于设置资源的类型,常用的有3个: application/jsonapplication/x-www-form-urlencoded,form 表单提交的格式。multipar…...
树形结构
树形结构广泛存在于客观世界中,如族谱、目录、社会组织、各种事物的分类等,都可用树形结构表示。树形结构在计算机领域应用广泛,如操作系统中的目录结构;源程序编译时,可用树表示源程序的语法结构;在数据库…...
《C++避坑神器·二十四》简单搞懂json文件的读写之根据键值对读写Json
c11 json解析库nlohmann/json.hpp文件整个代码由一个头文件组成 json.hpp,没有子项目,没有依赖关系,没有复杂的构建系统,使用起来非常方便。 json.hpp库在文章末尾下载 读写主要有两种方式,第一种根据键值对读写&…...
SQL进阶理论篇(二十一):基于SQLMap的自动化SQL注入
文章目录 简介获取当前数据库和用户信息获取MySQL中的所有数据库名称查询wucai数据库中的所有数据表查看heros数据表中的所有字段查询heros表中的英雄信息总结参考文献 简介 从上一小节,可以发现,如果我们编写的代码存在着SQL注入的漏洞,后果…...
xtu oj 1055 整数分类
Description 按照下面方法对整数x进行分类:如果x是一个个位数,则x属于x类;否则将x的各位上的数码累加,得到一个新的x,依次迭代,可以得到x的所属类。比如说24,246,则24的类别数是6&a…...
(2023|CVPR,Corgi,偏移扩散,参数高斯分布,弥合差距)用于文本到图像生成的偏移扩散
Shifted Diffusion for Text-to-image Generation 公众:EDPJ(添加 VX:CV_EDPJ 或直接进 Q 交流群:922230617 获取资料) 目录 0. 摘要 1. 简介 2. 方法 2.1 偏移扩散 3. 实验 3.1 无监督文本到图像生成 3.2 无…...
HTML 语义化
目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案: 语义化标签: <header>:页头<nav>:导航<main>:主要内容<article>&#x…...
AtCoder 第409场初级竞赛 A~E题解
A Conflict 【题目链接】 原题链接:A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串,只有在同时为 o 时输出 Yes 并结束程序,否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...
【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习
禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...
听写流程自动化实践,轻量级教育辅助
随着智能教育工具的发展,越来越多的传统学习方式正在被数字化、自动化所优化。听写作为语文、英语等学科中重要的基础训练形式,也迎来了更高效的解决方案。 这是一款轻量但功能强大的听写辅助工具。它是基于本地词库与可选在线语音引擎构建,…...
C++使用 new 来创建动态数组
问题: 不能使用变量定义数组大小 原因: 这是因为数组在内存中是连续存储的,编译器需要在编译阶段就确定数组的大小,以便正确地分配内存空间。如果允许使用变量来定义数组的大小,那么编译器就无法在编译时确定数组的大…...
Docker 本地安装 mysql 数据库
Docker: Accelerated Container Application Development 下载对应操作系统版本的 docker ;并安装。 基础操作不再赘述。 打开 macOS 终端,开始 docker 安装mysql之旅 第一步 docker search mysql 》〉docker search mysql NAME DE…...
Java数值运算常见陷阱与规避方法
整数除法中的舍入问题 问题现象 当开发者预期进行浮点除法却误用整数除法时,会出现小数部分被截断的情况。典型错误模式如下: void process(int value) {double half = value / 2; // 整数除法导致截断// 使用half变量 }此时...
STM32---外部32.768K晶振(LSE)无法起振问题
晶振是否起振主要就检查两个1、晶振与MCU是否兼容;2、晶振的负载电容是否匹配 目录 一、判断晶振与MCU是否兼容 二、判断负载电容是否匹配 1. 晶振负载电容(CL)与匹配电容(CL1、CL2)的关系 2. 如何选择 CL1 和 CL…...
DeepSeek源码深度解析 × 华为仓颉语言编程精粹——从MoE架构到全场景开发生态
前言 在人工智能技术飞速发展的今天,深度学习与大模型技术已成为推动行业变革的核心驱动力,而高效、灵活的开发工具与编程语言则为技术创新提供了重要支撑。本书以两大前沿技术领域为核心,系统性地呈现了两部深度技术著作的精华:…...
基于Python的气象数据分析及可视化研究
目录 一.🦁前言二.🦁开源代码与组件使用情况说明三.🦁核心功能1. ✅算法设计2. ✅PyEcharts库3. ✅Flask框架4. ✅爬虫5. ✅部署项目 四.🦁演示效果1. 管理员模块1.1 用户管理 2. 用户模块2.1 登录系统2.2 查看实时数据2.3 查看天…...
