想一想项目创建后升级npm依赖需要多长时间?如何知道当前项目的npm依赖项的“健康”?旧项目升级npm依赖有哪些注意事项?核心诉求是提高可维护性。不容易和后面介绍的依赖冲突。引入新特性,功能表现接近文档描述,后续开发也能得心应手。提高便携性。方便老项目迁移到更高版本的npm或pnpm。提高可靠性。只要依赖还在稳定迭代,升级肯定会引入一系列的bugfix(但也可能引入新的bug)。提高安全性。官方社区会及时通报npm所依赖的安全漏洞,将版本保持在安全范围内可以消除很多隐患。过程方法使用专业的评估工具。手动升级@latest无异于把依赖当作黑盒子。优先处理。集中精力升级有安全隐患的核心依赖和库,否则时间投入很容易超出预期。阅读变更日志以评估升级的影响。回归测试非常重要。除了回归测试,领导治理的人不仅要熟悉项目内容,还要对计划升级的npm包有充分的了解。如果没有合适的人选,建议继续在代码堆坚持一段时间。毕竟升级有风险,后果自负。检索工具以下内容以npm为例,pnpm和yarn有替代命令。过时的依赖项npmoutdatednpmoutdated命令检查来自npm源的已安装包是否有过时的依赖项。仅以几个包为例:PackageCurrentWantedLatestLocationaxios0.18.10.18.10.27.2project-dirlog4js2.11.02.11.06.5.2project-dirlru-cache4.1.54.1.57.10.2project-dirsocket.io2.4.12.5.04.5.1项目-dirvue2.6.142.6.143.2.37项目-dirvue-lazyload1.3.31.3.43.0.0-rc.2项目-dirvue-loader14.2。414.2.417.0.0project-dirvue-router3.5.33.5.44.0.16project-dirvuex3.6.23.6.24.0.2project-dirwebpack3.12.03.12.05.73.0project-dir只会默认检查项目package.json中直接引用的依赖,使用--all选项可以匹配所有依赖。不过没必要,如果真的要彻底升级,建议尝试重建锁文件。对于过时的包,使用npmupdate或者其他包管理工具对应的update命令安装SemVer标准并进行升级。如果要跨Major版本,需要手动指定升级版本。风险依赖npmauditnpmaudit命令还会向npm源发起请求,它以package-lock.json为参数,返回已知漏洞的依赖列表。也就是说,audit可以在不安装node_modules的情况下执行,其结果完全依赖于当前的package-lock.json。返回节选如下:#Runnpminstallswiper@8.2.5toresolve1vulnerabilitySEMVERWARNING:Recommendedactionisapotentiallybreakingchange┌────────────────┬─────────────────────────────────────────────────────────────┐│严重│swiper中的原型污染│├────────────────┼──────────────────────────────────────────────────────────────┤│套餐│swiper│├────────────────┼──────────────────────────────────────────────────────────────┤││swiper的依赖│├────────────────┼───────────────────────────────────────────────────────────┤│路径│刷卡器│├────────────────┼────────────────────────────────────────────────────────——————┤│更多信息│https://github.com/advisories/GHSA-p3hc-fv2j-rp68│└──────────────────┴────────────────────────────────────────────────────────────────────────────────────────────────────────────┘在2502个扫描包中发现了125个漏洞(8个低,66个中等,41个高,10个严重)运行`npmauditfix`来修复其中的15个。96个漏洞需要semver-major依赖更新。有关详细信息,请参阅完整报告。如果发现执行结果是404,说明当前源不支持审计接口,可以换成官方支持审计的源,执行npmhttpfetchPOST404https://registry.npmirror.com//npm/v1/security/audits306msnpm错误!代码ENOAUDITnpm错误!审核您配置的注册表(https://registry.npmmirror.com/)不支持审核requests.npmERR!auditTheserversaid:
404NotFound
虽然结果中提到了npmauditfix命令,但它并不总是可靠的。它能修复的依赖是有限的,远不如升级根依赖带来的间接依赖数量那么明显。Implicitdependenciesnpxdepchecknpmcli工具depcheck可以帮我们找到项目中Unuseddependencies(无用依赖)和Phantomdependencies(虚幻依赖),分别表示写到package.json中但没有被项目使用,被引用项目但未写入包.json。depcheck更像是一个过滤器,用来缩小调查范围,其打印出来的结果是不可信任的。例如,默认情况下depcheck不识别特殊安装的插件。未使用的依赖项*剪贴板*cross-env*firebase*代理*路由缓存*socket.io/build/utils.js删除无用的依赖,必须熟悉npm包的使用性质,然后用??grep工具反复确认。Zombiedependenciesnpminstall最后,需要提防一种类型的Zombie依赖项。与前面介绍的隐式依赖不同,它是非常有害的。首先,它实际上被项目使用,但已被维护者弃用或存档。表示版本不再更新,包名不会出现在过期列表中;很可能没有人报告错误,它不会出现在审核列表中。但是潜在的bug没有人修复,它会一直躲在项目里,伺机而动。作者没有找到合适的工具来查找僵尸依赖,只好多关注npminstall的deprecatedlog。CHANGELOG阅读治理建议Changelog一般放在代码仓库的CHANGELOG.md或History.md中,随意的也可以放在Github的releases页面,正式的会放在官方的Migrations类网站。如果你发现一个npm包没有changelog,或者changelog写得不好,建议换成其他更可靠的替代品,只能靠阅读提交。关键词(欢迎补充):BREAKINGCHANGE!Node.js开发者一般使用上述方法来标记不兼容的更改。锁文件版本管理这个建议是针对商业软件的开发过程。活跃的开源场景不需要锁文件,让开发者在迭代和测试过程中及早发现兼容性问题。package-lock.json的设计文档直截了当地建议将锁文件添加到代码仓库:以确保团队成员和CI可以使用完全相同的依赖项。作为node_modules的轻量级备份。使对依赖关系树的更改更加明显。加快安装过程。然而,npm依赖管理策略因团队和项目而异。是否提交锁文件到git仓库可以根据需要选择,版本管理有多种形式。比如研发流程完善,每次释放的锁文件都会保留在产品库或镜像中,随时可以恢复。但是,如果缺乏相关措施,就需要想办法备份生产环境的锁文件,为问题复现和故障恢复提供依据。updatehoisting已经更新多年,很多package-lock.json的外层依赖的版本会滞后于子节点,因为目前npm不会为了保持最小更新范围而对锁树进行旋转变形。即使较新的项目直接依赖latest,它的间接依赖也可能还是旧的,以至于现有的依赖提升结果与默认提升算法的偏差越来越大。一些老项目在脱离package-lock.json文件后甚至无法正常安装构建。此时,依赖关系已经处于非常不健康的状态。开发者需要担心新引入的依赖会不会破坏平衡。他们无法迁移npm包管理工具,也无法升级Node.js版本。但是修复它并不复杂,而且比修复没有package-lock.json的项目要好。生成可靠的package-lock.json的最简单方法是删除旧的并引入新的:rm-rfpackage-lock.jsonnode_modulesnpmi更好的方法是切换到不使用提升的依赖管理工具。情况弄清楚了,什么时候重建就可以看自己的需要了。不过把锁文件加到.gitignore里的同学要注意了。如果别人有你本地无法重现的问题,记得先删除package-lock.json。dependencies和devDependencies的区别在整理dependencies和devDependenciespackage.json中就不用介绍了,但是会在项目中严格区分吗?首先,devDependencies是为了优化npm包的依赖而设计的,作为应用的项目通常不会打包发布到npm;第二,没有区别,没有直接的不利后果。所以经常有小伙伴直接把开发环境依赖的工具安装成dependencies。然而,即使对于项目,devDependencies也有积极的意义:它们可以在语义上划定依赖项的使用。使用npminstall--production忽略devDependencies,提高安装效率,显着减小node_modules的大小。第二点需要补充一下。由于静态项目的搭建环境往往需要安装devDependencies中的大部分依赖,一般只有运行在服务器上的Node.js项目才需要考虑这样做。但是随着TypeScript的普及或者SSR的引入,这些服务端项目也需要先构建再运行。那有什么用?别忘了,还有一个npmprune--production可以用作后期项目大小优化。当然,语义分区可以提供足够的帮助,例如基于依赖关系优化npm治理优先级和策略。对了,dependencies和devDependencies不是用来区分重要程度的。请不要将运行可选的依赖项放在devDependencies中,而是放在optionalDependencies(https://docs.npmjs.com/cli/v6/configuring-npm/package-json#optionaldependencies)中。结束语上面介绍的经验主要是一个概述。主要结合了npm依赖管理工具的特点,没有介绍yarn、pnpm等工具的独特API和问题。如果读者想了解更多,请参阅相关文件。另外,同时使用多个依赖管理工具的项目相当复杂,也比较少见。本文不做分析,不建议读者朋友尝试。在软件工程领域,依赖治理还有很多点需要我们进一步实践,但内容更侧重于重构。回到slogan中提到的项目依赖的“健康”,描述依赖关系的混乱程度,其实是作者胡说八道。不做这些依赖治理也没关系,因为软件的生命周期往往不会持续到依赖崩溃的那一天。但是杂乱的依赖管理很容易导致代码损坏。