🧑 写在开头
点赞 + 收藏 === 学会🤣🤣🤣
有这样一种场景:如果你在开发过程中,发现某个npm包有Bug,应该怎么办?
第一选择当然是向原作者提issue,或者Fork该仓库代码,修改以后,提交合并请求。
但这种情况有个严重的问题,就是耗时,如果遇到严格的作者,或者不活跃的作者,时间线可能会拉得很长。你的项目未必能等这么长时间。
还有一种可能是,你修改的代码并不具备普适性,只有你的业务场景能用到,合并被拒的概率会大大增加。
总而言之,如果能修改npm包的源包,再好不过,如果不行,则需要有个临时方案,或者替代方案。
这时,又有下面两种情况:
- 代码量少,可以直接修改npm包代码的,考虑补丁方案。
- 代码量多,或者npm包代码是压缩混淆过的,不具备修改条件。修改源码后,再修改包名,重新发布,在应用代码中更换引用。为叙文方便,我将这种方案命名为换日方案(偷天换日,李代桃僵)。
下面,详细介绍下这两种不同方案。
补丁方案
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或性能问题,通常不必追求新的版本。
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/29ba74c7c7ffd7aa157831c6436d3738 Once 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 } }
pnpm功能非常强大,后面我会再详细写篇文章介绍下。
总结
在开发过程中发现npm包的Bug,首先向原作者提交issue或Fork代码修改后提交合并请求。但遇到不活跃或拒绝修改的情况,项目等待时间会很长。这时可以使用补丁方案或换日方案进行解决。
补丁方案中,如果是npm或yarn v1,可以使用patch-package工具包处理;如果是yarn v2或pnpm,可以使用各自的patch命令。
换日方案,则是修改源码,发布新的npm包后,利用pnpm的别名功能,将所有依赖原npm包的地方,全部替换为新的包。
这种场景在日常开发中还是比较常见的,这里为大家提供一种思路。当然,如果真是个Bug,别忘了提issue或PR,为开源贡献自己的一份力量,在与作者的沟通交流中,相信你也能受益匪浅。
本文转载于:https://juejin.cn/post/7356534347509497919
如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。
1.本站内容仅供参考,不作为任何法律依据。用户在使用本站内容时,应自行判断其真实性、准确性和完整性,并承担相应风险。
2.本站部分内容来源于互联网,仅用于交流学习研究知识,若侵犯了您的合法权益,请及时邮件或站内私信与本站联系,我们将尽快予以处理。
3.本文采用知识共享 署名4.0国际许可协议 [BY-NC-SA] 进行授权
4.根据《计算机软件保护条例》第十七条规定“为了学习和研究软件内含的设计思想和原理,通过安装、显示、传输或者存储软件等方式使用软件的,可以不经软件著作权人许可,不向其支付报酬。”您需知晓本站所有内容资源均来源于网络,仅供用户交流学习与研究使用,版权归属原版权方所有,版权争议与本站无关,用户本人下载后不能用作商业或非法用途,需在24个小时之内从您的电脑中彻底删除上述内容,否则后果均由用户承担责任;如果您访问和下载此文件,表示您同意只将此文件用于参考、学习而非其他用途,否则一切后果请您自行承担,如果您喜欢该程序,请支持正版软件,购买注册,得到更好的正版服务。
5.本站是非经营性个人站点,所有软件信息均来自网络,所有资源仅供学习参考研究目的,并不贩卖软件,不存在任何商业目的及用途
暂无评论内容