当前位置: 首页 > news >正文

修改第三方npm包

文章目录

  • 一、前言
  • 二、补丁方案
    • 2.1、`patch-package`
    • 2.2、`pnpm patch`
  • 三、换日方案
  • 四、总结
  • 五、最后

一、前言

在开发过程中,发现某个npm包有Bug,应该怎么办?可以试试下面这2种方案:

  1. 代码量少,可以直接修改npm包代码的,考虑补丁方案。
  2. 代码量多,或者npm包代码是压缩混淆过的,不具备修改条件。修改源码后,再修改包名,重新发布,在应用代码中更换引用。为叙文方便,我将这种方案命名为换日方案(偷天换日,李代桃僵)。

二、补丁方案

2.1、patch-package

patch-package是一个用于修复第三方依赖包的工具,使用方式非常简单。

它支持npmyarn 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.jsonscripts中加入"postinstall": "patch-package"

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

这样当其他同事拉下代码,运行npm install或是yarn install命令时,便会自动为依赖包打上我们的补丁了。

简单来说,这个方案的原理就是记录补丁的代码与位置,利用npmhookpostinstall会在npm install后触发),在安装完依赖以后,触发相应的脚本,将补丁覆盖到node_modules对应的包里。

当然,补丁是对应具体版本的,需要锁定版本号。这样的缺点是如果要升级的话,还得重新来一遍,不过不是有Bug或性能问题,通常不必追求新的版本。

2.2、pnpm patch

pnpmpatch自称灵感来自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"

按照提示,打开这个文件夹,加一行代码:

img

执行上面控制台的提示:

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,打开以后,你就能找到添加的代码:

img

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

img

删除node_modules,重新pnpm i安装依赖,仍然与现在一样,这就代表成功了。

整个流程下来,我们看得出来相比于patch-package,要稍微复杂点儿,但也是可以接受的。

注意:patches目录是一定得提交到git的。

三、换日方案

如果要修改的代码较多,或者不具备修改条件,这时就需要修改源码。到GitHub上找到npm包的源码,Fork该项目,修改代码后,再修改包名,重新发布,比如你要修改的包是lodash,可以修改为awesome-lodash,在应用代码中更换引用。

本来这个方案没什么好说的,但有一种情况,如果你修改的是个底层包,也就是说并不是你的应用代码中直接引用的,而是你引用的npmA所依赖的,甚至可能同时被包B依赖的,这时就比较尴尬了,你不可能再去修改AB的源码,那就太不值当了。

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,首先向原作者提交issueFork代码修改后提交合并请求。但遇到不活跃或拒绝修改的情况,项目等待时间会很长。这时可以使用补丁方案或换日方案进行解决。

补丁方案中,如果是npmyarn v1,可以使用patch-package工具包处理;如果是yarn v2pnpm,可以使用各自的patch命令。

换日方案,则是修改源码,发布新的npm包后,利用pnpm的别名功能,将所有依赖原npm包的地方,全部替换为新的包。

这种场景在日常开发中还是比较常见的,这里为大家提供一种思路。当然,如果真是个Bug,别忘了提issuePR,为开源贡献自己的一份力量,在与作者的沟通交流中,相信你也能受益匪浅。

五、最后

本人每篇文章都是一字一句码出来,希望对大家有所帮助,多提提意见。顺手来个三连击,点赞👍收藏💖关注✨,一起加油☕

相关文章:

修改第三方npm包

文章目录 一、前言二、补丁方案2.1、patch-package2.2、pnpm patch 三、换日方案四、总结五、最后 一、前言 在开发过程中&#xff0c;发现某个npm包有Bug&#xff0c;应该怎么办&#xff1f;可以试试下面这2种方案&#xff1a; 代码量少&#xff0c;可以直接修改npm包代码的&…...

Redis性能优化:关键配置和最佳实践

大家好&#xff0c;我是升仔 Redis作为一个高性能的键值存储系统&#xff0c;在现代应用架构中扮演着至关重要的角色。性能优化是Redis部署与维护中的一个关键环节。本文将从关键配置、持久化配置、实践场景和异常处理配置等方面&#xff0c;详细介绍如何优化Redis的性能。 关…...

华为数通方向HCIP-DataCom H12-831题库(多选题:241-249)

第241题 (NEW) 以下哪些操作可能会影响客户网络的正常运行? A、从设备上下载日志 B、软件升级 C、路由协议配置变更 D、debug核心交换机上转发的所有IP报文 答案:ABCD 解析: 第242题 对于防火墙的默认安全区 Trust 和 Untrust 的说法,正确的有 A、从 Trust 区域访问 Untr…...

typeorm联表查询:副表json格式放到主表字段下或多个副表字段并列主表字段

实体类字段不做映射&#xff0c;typeorm实现联查查询 1、副表json格式放到主表字段下 //goods表和member表联表&#xff0c;关系goods.id member.uid&#xff0c;member表数据json对象格式放到主表userInfo下 //leftJoinAndMapOne配合getMany实现 const builder await getCo…...

Flume采集日志存储到HDFS

1 日志服务器上配置Flume,采集本地日志文件&#xff0c;发送到172.19.115.96 的flume上进行聚合&#xff0c;如日志服务器有多组&#xff0c;则在多台服务器上配置相同的配置 # Name the components on this agent a1.sources r1 a1.sinks k1 a1.channels c1# Describe/con…...

redis—String字符串

目录 前言 1.字符串数据类型 2.常见命令 3.典型应用场景 前言 字符串类型是Redis最基础的数据类型&#xff0c;关于字符串需要特别注意: 1)首先Redis中所有的键的类型都是字符串类型&#xff0c;而且其他几种数据结构也都是在字符串类似基础.上构建的&#xff0c;例如列表…...

三相电机转差率为负值的情形

1.电机开始发电的特征 注意&#xff0c;电机因为有输入频率对原始旋转磁场的影响&#xff0c;在正常工作时&#xff0c;应该处于稳态&#xff0c;因为旋转磁场决定了这个系统的运转方向和运转的大致频率区间。它会处于力矩平衡态。但是&#xff0c;如果&#xff0c;此时电机处…...

关于Dark Frost 僵尸网络对游戏行业进行DDoS攻击的动态情报

一、基本内容 近期&#xff0c;一种名为Dark Frost 的新型僵尸网络被发现正在对游戏行业发起分布式拒绝服务攻击&#xff08;DDoS)。目标包括游戏公司、游戏服务器托管提供商、在线流媒体甚至和网络信息安全攻击者直接交互的其他游戏社区成员。截至2023年2月&#xff0c;僵尸网…...

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、相关的学习链接 前言&#xff1a;最近在学习前端补齐我的软件技能树&#xff0c;最近简单总结一下 1、学习路线 基本&#xff1a;vue3、ts(js)、 vite、eslint、css(动画、布局) 依赖包&#xff1a;vue-router、vue-i18…...

Vue实现响应式布局

前提准备&#xff1a;响应式布局有两种方法&#xff0c;看自己想要哪种。 方法一&#xff1a;百分比 用百分比去写元素的宽度&#xff0c;然后让子元素撑起父元素的高度 .parent {width: 50%; }.child {width:100%;height:100px; } 方法二&#xff1a;vh、vw vw、vh是基于视…...

linux:下载、网络请求、端口

一&#xff1a;ping命令 可以通过ping命令,检查指定的网络服务器是否是可联通状态 语法: ping [-c num] ip或主机名 1、选项&#xff1a;-c,检查的次数&#xff0c;不使用-c选项&#xff0c;将无限次数持续检查 2、参数&#xff1a;ip或主机名&#xff0c;被检查的服务器的…...

182.【2023年华为OD机试真题(C卷)】敏感字段加密(字符串的分割、替换和拼接实现JavaPythonC++JS)

请到本专栏顶置查阅最新的华为OD机试宝典 点击跳转到本专栏-算法之翼:华为OD机试 🚀你的旅程将在这里启航!本专栏所有题目均包含优质解题思路,高质量解题代码,详细代码讲解,助你深入学习,深度掌握! 文章目录 【2023年华为OD机试真题(C卷)】敏感字段加密(字符串…...

新版IDEA中Git的使用(三)

说明&#xff1a;前面介绍了在新版IDEA中Git的基本操作、分支操作&#xff0c;本文介绍一下在新版IDEA中&#xff0c;如何回滚代码&#xff1b; 分以下三个阶段来介绍&#xff1a; 未Commit的文件&#xff1b; 已经Commit&#xff0c;但未push的文件&#xff1b; 已经push的…...

node - koa 获取 Content-Type: text/plain 的数据

目录 1&#xff0c;Content-Type2&#xff0c;koa 获取请求的数据 1&#xff0c;Content-Type Content-Type HTTP 标头用于设置资源的类型&#xff0c;常用的有3个&#xff1a; application/jsonapplication/x-www-form-urlencoded&#xff0c;form 表单提交的格式。multipar…...

树形结构

树形结构广泛存在于客观世界中&#xff0c;如族谱、目录、社会组织、各种事物的分类等&#xff0c;都可用树形结构表示。树形结构在计算机领域应用广泛&#xff0c;如操作系统中的目录结构&#xff1b;源程序编译时&#xff0c;可用树表示源程序的语法结构&#xff1b;在数据库…...

《C++避坑神器·二十四》简单搞懂json文件的读写之根据键值对读写Json

c11 json解析库nlohmann/json.hpp文件整个代码由一个头文件组成 json.hpp&#xff0c;没有子项目&#xff0c;没有依赖关系&#xff0c;没有复杂的构建系统&#xff0c;使用起来非常方便。 json.hpp库在文章末尾下载 读写主要有两种方式&#xff0c;第一种根据键值对读写&…...

SQL进阶理论篇(二十一):基于SQLMap的自动化SQL注入

文章目录 简介获取当前数据库和用户信息获取MySQL中的所有数据库名称查询wucai数据库中的所有数据表查看heros数据表中的所有字段查询heros表中的英雄信息总结参考文献 简介 从上一小节&#xff0c;可以发现&#xff0c;如果我们编写的代码存在着SQL注入的漏洞&#xff0c;后果…...

xtu oj 1055 整数分类

Description 按照下面方法对整数x进行分类&#xff1a;如果x是一个个位数&#xff0c;则x属于x类&#xff1b;否则将x的各位上的数码累加&#xff0c;得到一个新的x&#xff0c;依次迭代&#xff0c;可以得到x的所属类。比如说24&#xff0c;246&#xff0c;则24的类别数是6&a…...

(2023|CVPR,Corgi,偏移扩散,参数高斯分布,弥合差距)用于文本到图像生成的偏移扩散

Shifted Diffusion for Text-to-image Generation 公众&#xff1a;EDPJ&#xff08;添加 VX&#xff1a;CV_EDPJ 或直接进 Q 交流群&#xff1a;922230617 获取资料&#xff09; 目录 0. 摘要 1. 简介 2. 方法 2.1 偏移扩散 3. 实验 3.1 无监督文本到图像生成 3.2 无…...

[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?

&#x1f9e0; 智能合约中的数据是如何在区块链中保持一致的&#xff1f; 为什么所有区块链节点都能得出相同结果&#xff1f;合约调用这么复杂&#xff0c;状态真能保持一致吗&#xff1f;本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里&#xf…...

【kafka】Golang实现分布式Masscan任务调度系统

要求&#xff1a; 输出两个程序&#xff0c;一个命令行程序&#xff08;命令行参数用flag&#xff09;和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽&#xff0c;然后将消息推送到kafka里面。 服务端程序&#xff1a; 从kafka消费者接收…...

【Linux】shell脚本忽略错误继续执行

在 shell 脚本中&#xff0c;可以使用 set -e 命令来设置脚本在遇到错误时退出执行。如果你希望脚本忽略错误并继续执行&#xff0c;可以在脚本开头添加 set e 命令来取消该设置。 举例1 #!/bin/bash# 取消 set -e 的设置 set e# 执行命令&#xff0c;并忽略错误 rm somefile…...

进程地址空间(比特课总结)

一、进程地址空间 1. 环境变量 1 &#xff09;⽤户级环境变量与系统级环境变量 全局属性&#xff1a;环境变量具有全局属性&#xff0c;会被⼦进程继承。例如当bash启动⼦进程时&#xff0c;环 境变量会⾃动传递给⼦进程。 本地变量限制&#xff1a;本地变量只在当前进程(ba…...

椭圆曲线密码学(ECC)

一、ECC算法概述 椭圆曲线密码学&#xff08;Elliptic Curve Cryptography&#xff09;是基于椭圆曲线数学理论的公钥密码系统&#xff0c;由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA&#xff0c;ECC在相同安全强度下密钥更短&#xff08;256位ECC ≈ 3072位RSA…...

ssc377d修改flash分区大小

1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...

iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版​分享

平时用 iPhone 的时候&#xff0c;难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵&#xff0c;或者买了二手 iPhone 却被原来的 iCloud 账号锁住&#xff0c;这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...

从零实现STL哈希容器:unordered_map/unordered_set封装详解

本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说&#xff0c;直接开始吧&#xff01; 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...

【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分

一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计&#xff0c;提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合&#xff1a;各模块职责清晰&#xff0c;便于独立开发…...

Hive 存储格式深度解析:从 TextFile 到 ORC,如何选对数据存储方案?

在大数据处理领域&#xff0c;Hive 作为 Hadoop 生态中重要的数据仓库工具&#xff0c;其存储格式的选择直接影响数据存储成本、查询效率和计算资源消耗。面对 TextFile、SequenceFile、Parquet、RCFile、ORC 等多种存储格式&#xff0c;很多开发者常常陷入选择困境。本文将从底…...