公司内部的 NPM 因为一些固有的 bug 经常被吐槽,最近刚好有时间可以来做优化,然后就尝试解一下之前遇到的一个 publish 的 bug,下边是分析记录。
公司内网 NPM 选择的是使用 verdaccio 来做服务,目前遇到了一个模块 publish 时包含 deprecated 字段导致历史版本丢失,仅剩下本次 publish 的版本信息。
NPM CLI 实现 deprecate 的时候流程是这样的:
https://github.com/npm/cli/blob/latest/lib/commands/deprecate.js
然后新增模块在 CLI 的实现是:
https://github.com/npm/libnpmpublish/blob/main/publish.js
Verdaccio 在实现 server 的时候,更新模块和上传模块是同一个服务接口,两个动作之间又没有处理好:https://github.com/verdaccio/verdaccio/blob/master/packages/api/src/publish.ts#L148
此部分逻辑为 deprecated 处理逻辑:https://github.com/verdaccio/verdaccio/blob/master/packages/api/src/publish.ts#L306-L322
local-storage 处理逻辑:https://github.com/verdaccio/verdaccio/blob/master/packages/store/src/local-storage.ts#L408
这里删除了无效版本的信息:https://github.com/verdaccio/verdaccio/blob/master/packages/store/src/local-storage.ts#L429-L440
举例场景,如果已经有一个模块存在 1.0.0、1.0.1 的版本,那么触发 publish 上传 1.0.2 版本的时候服务接收到的数据是这样的:
{
"name": "module\_name",
"version": {
"1.0.2": {
"deprecated": "xxx" // 如果有的话
},
}
}
而如果直接调用 npm deprecate module_name@1.0.0 "xxx" 的时候服务接收到的数据是这样的:
{
"name": "module\_name",
"version": {
"1.0.0": {
"deprecated": "xxx" // 如果有的话
},
"1.0.1": {}
}
}
而两者在服务端的处理逻辑是一样的:
最终导致如果 publish 的时候 package.json 中包含 deprecated 参数则会出现历史版本丢失的情况。
修复方式也比较简单,其实主要就是能够区分出当前接口触发是 deprecate 导致的还是 publish 导致的就可以了。
那么我们就通过手动读取一次当前模块的 versions 信息,然后对比本次接口触发时接收到的 metadata,如果是 publish,那么这里一定不会匹配上的。
那么就可以在触发 deprecated 的时候新增一个检测,检测是否为 publish 时携带了 deprecated,这种情况直接忽略,进入原有的新模块上传流程。
总结来说,deprecated 字段更像是一个 NPM 内部约定的字段,而非一个需要使用者写到 package.json 中的显性字段,如果需要对版本添加废弃信息,请用官方推荐的方案:https://doc.codingdict.com/npm-ref/cli/deprecate.html
以及已经把 PR 提给官方了,期待一波回复:https://github.com/verdaccio/verdaccio/pull/2766
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。