2017-01-14 22:42:59

NPM包管理的一点思考

十二月某天早上睡醒时,发现某个微信群中有一位群友在求助:vue-cli创建的项目构建失败,提示selectColor(namespae);代码中namespae不存在。

当时没有引起关注,但是一上班,发现同事都在讨论:NPM包再次爆炸了一次。

和历史惊人的相似:被babel直接依赖的debug模块写错了一个字母,导致当时成千上万次的转码全部失败

实时记录

debug爆炸后,众人才发现如此流行的库竟然连一个确保主流程通畅的CI都没有

上图的两哥么表示,一个简单的静态分析工具都能检查出这种拼写错误,怎么直接就发布了?下面的哥么比较直接,说部署前至少跑一下eslint好吗

写py的哥么跑来凑热闹了,他表示这锅得node的生态圈(其实这里专指npm)背,博主认为确实得npm背一部分锅。

这时候,站出了一名提供临时解决办法的人士,他提出了两种方法,要么提PR,要么锁版本,并认为楼上全在指责而不动手帮助debug的维护者并不正确。

维护者终于跳出来修掉了这个"荒唐"的bug,并表示这就加上lint以及test。

接下来有人表示<( ̄3 ̄)> 哇修的好快啊赞,有人表示“害苦我了”(真中文),然后TJ说了一段话,我觉得作为这个issue的结束挺适合的:

TJ表示,对于你经常使用的项目,要么捐钱,要么捐时间(发PR),否则开源的氛围会越来越差。

分锅大会

博主总结一下上面issue中众人的观点,这锅得分成如下几个部分,其实,在任意部分都有可能完全避免掉debug出现的这种问题。

  • npm的包依赖默认使用动态版本
    • dependencies版本号前面的^不是正则,而是表示大版本相同,因此,如果你以前是用1.0.0开发,那么现在的1.5.0或者1.9.0都会被npm默认安装,是不是坑死了?
  • debug改错了一个字母
    • 功能没变,出现这种情况的概率真的很低,大概是打哈欠时手一不小心碰到了delete键罢
  • debug没有使用lint,也没有test
    • 俩者即使做到一件,也不会出现这种问题

接下来则是issue上TJ总结的,在出现这种破坏大范围构建的非常规时间内,指责不会让构建成功,而应当立即找到解决办法,发PR最好。锅是分不到指责的那些人头上的,但是道义上来说我并不赞同那些人。

一些思考

针对npm的包依赖

npm默认安装动态版本实在是太坑爹了,dependencies版本号前面的^会误导所有没读过npm官方文档的用户,因为所有第一次使用npm甚至使用数年npm的用户,都会以为^符号是Javascript的正则

因此,最好立即把package.json中的^符号全给删掉,这可以帮助你避免很多潜在的包依赖带来的问题。

实际上,npm有一个命令叫shrinkwarp,可以生成一个json文件锁住所有依赖的版本,但是并没有作为默认选项,并且在前端项目中经常锁版本失败。
yarn解决了这个问题的一部分。因为,npm目前没有办法锁住node_modules中包的依赖,但Facebook的yarn已经可以通过yarn lock将依赖的依赖也锁定版本,为了保证开发与线上环境一致,请从现在开始使用yarn吧。

更好的办法,则是在锁住版本的同时,在依赖有新版本的情况下通知维护者,由维护者决定此依赖是否可以升级,决定的条件最好是CI。
国外有一个GreenKeeper做了这件事,我们在内部也接入了一些类似的系统,恰好最近博主的教训(在博主前一篇文章末尾有介绍)很深刻。

另外,CommonJS运行时加载(require是同步的)的套路,能不能早点进化到ES6 module啊?有ES6 module,不需要lint同样可以静态分析出debug这次的问题。

现在,

针对debug的问题

debug在爆炸前并没有一个很好的团队规范,理论上来说,即使只有两个人的项目,都需要定好lint以及保证test,甚至习惯OOP的用户还会考虑typescript来避免弱类型带来的边界问题

在这一点上,我认为有5%的责任在于选择了debug包作为依赖的库及其维护者,他们在使用时并没有提醒debug添加test,甚至有可能从来都没有关注过测试覆盖率

没有尾声

没有尾声,看客可能看热闹很爽,在事件解决后会逐渐散去,但是如果你是真正的Javascript工程师,你会以为debug爆炸一次就完了?npm动态版本没解决前,一定有下一个debug再次爆炸的,而非常巧合的是,这个下一个正好又是debug。

短短十天之后,debug再次爆炸, 这次是babel强行导入了debug/node.js文件这个非官方的API入口,而debug官方根本不知道有人使用这个入口所以移除了。

这锅得babel背,babel不按套路来确实怪不到debug身上,所以,上文我提到的5%这个数值,我觉得还是挺合适的。

开源开源,程序员在开源中获益不菲,也因此碰到开源产品中遇到的各种问题。
这种情况在Javascript生态圈中尤为突出,作为github最活跃也是最近几年最狂飙突进的语言,Javascript生态圈出现的任何问题,都会被其他语言圈所放大。
npm包数以万计,是世界上最成功的包管理器,没有之一。在享受它带来的好处时,如果你认为伴随而来的问题太多,并光指责而不行动起来解决,那么我只想说:

升米恩斗米仇

Javascript生态圈在开源中源源不断地获利,又向开源源源不断地贡献,于烈焰与寒冰之间,它向着某个方向前行

本文链接:https://smallpath.me/post/npm-dependency-version-control

-- EOF --