前端架构思考:代码复用带来的隐形耦合,可能让大模型造轮子是更好的选择-从 CDN 依赖包被删导致个站打不开到数年前因11 行代码导致上千项目崩溃谈谈npm黑洞 - 统计下你的项目有多少个依赖吧!

简介: 最近,我的个人网站因免费CDN上的Vue.js包路径变更导致无法访问,引发了我对前端依赖管理的深刻反思。文章探讨了NPM依赖陷阱、开源库所有权与维护压力、NPM生态问题,并提出减少不必要的依赖、重视模块设计等建议,以提升前端项目的稳定性和可控性。通过“left_pad”事件及个人经历,强调了依赖管理的重要性和让大模型代替人造轮子的潜在收益

最近,我的个站由于用到了免费CDN(国外的因为访问问题,改成了国内的bootcdn)上的一个vuejs包,当时是为了加速,但是没想到它这些年变了,一些包路径变了/没有进行缓存,导致整个站点无法访问。我开始反思前端工程中的依赖管理问题,尤其是某些优化,我之所以使用公开的库,是为了增加命中率,让用户打开网站的速度快一些,而不是重新从我的服务器下载个一模一样的文件。在搜索相关问题的过程中,我发现早在几年前,NPM 上的 "left_pad" 包被作者删除时,整个前端社区的项目纷纷遭遇了崩溃,印象到了数千项目的部署。

今天,呼吁大家反思一下:我们的前端项目设计的过于复杂(超过实际的复杂)、依赖是不是太多了!

先发起一个呼吁:前端使用第三方依赖时,优选下0依赖的包。发布新包时,不妨造造轮子

NPM 依赖陷阱:循环、深层的依赖

下图清晰的说明了npm黑洞问题:
f65b0d5825eb454ca70fbff39f49f1f9.jpeg

例如我随便打开了一个package.lock文件,就有5000行,这还只是一个只有一个页面的vue3+vite项目的单页应用,依赖也仅仅是包含:

 "dependencies": {
   
    "@ant-design/icons-vue": "^7.0.1",
    "ant-design-vue": "4.x",
    "dayjs": "^1.11.11",
    "pinia": "^2.1.7",
    "rxjs": "^7.8.1",
    "vue": "^3.4.29",
    "vue-i18n": "^9.13.1",
    "vue-router": "^4.4.0"
  },
  "devDependencies": {
   
    "@intlify/unplugin-vue-i18n": "^4.0.0",
    "@types/node": "^20.14.9",
    "@vitejs/plugin-vue": "^5.0.5",
    "@vitest/ui": "^1.6.0",
    "@vue/test-utils": "^2.4.6",
    "autoprefixer": "^10.4.19",
    "jsdom": "^24.1.0",
    "postcss": "^8.4.39",
    "sass": "^1.77.6",
    "sass-loader": "^14.2.1",
    "tailwindcss": "^3.4.4",
    "typescript": "^5.2.2",
    "unplugin-vue-components": "^0.27.2",
    "vite": "^5.3.1",
    "vitest": "^1.6.0",
    "vue-tsc": "^2.0.21"
  }

但是,实际安装的包有数百个,很多都是二次依赖、三次依赖。

11行代码影响上万个项目的发布事件

前端开发中,NPM 依赖的数量往往让人瞠目结舌。一个简单的前端项目可能引入数百个包,而每个包可能又有成百上千的二次依赖。这种依赖链的复杂性使得我们难以全面掌控项目中的所有外部模块,也增加了潜在的脆弱性。一个上游包的更新或删除,可能直接影响到数千个甚至上万个下游项目,正如 "left_pad" 事件所展示的那样。

"left_pad" 是一个只有 11 行代码的小工具,其代码如下:

module.exports = leftpad;
function leftpad (str, len, ch) {
   
  str = String(str);
  var i = -1;
  if (!ch && ch !== 0) ch = ' ';
  len = len - str.length;
  while (++i < len) {
   
    str = ch + str;
  }
  return str;
}

但它被删除后,立即导致了大量依赖它的项目无法正常工作。这样一个小工具的失效引发的连锁反应,不仅是对整个前端社区的警醒,更是让我们意识到我们对这些工具的过度依赖。

这个事件中,一位开发者因为对管理方式不满而选择删除了自己在 NPM 上发布的所有包,包括 "left_pad"。由于许多流行的前端库直接或间接依赖于这个小工具,导致数千个项目在构建过程中失败,甚至一些大型企业的服务也因此受到影响。这次事件让开发者意识到,尽管一个工具看起来非常小,但它在整个生态中的影响可能非常大。这样的事情让我们不禁感叹,前端生态系统在享受模块化开发带来便利的同时,也存在着巨大的隐患。

详细的可搜索 left pad事件 或者 查看 或许无法访问的维基百科

所有者当时的发言是:

这个库是我创建的,我有权删除

开源库的使用问题:所有权与维护压力

除了依赖的复杂性,开源库的所有权和维护问题也成为了前端社区不可忽视的隐患。许多清理类、工具类的小型开源库被大量使用,但这些库的所有权仍然掌握在个人开发者手中,这意味着开发者有完全的权利删除或停止维护这些库。例如 "left_pad" 的创建者认为这个库是他创建的,因此他有权利删除它。这种所有权问题让整个社区的稳定性变得不可预测。

此外,许多开源库虽然被大公司广泛使用,但它们的维护者可能只是一位个人开发者,并没有从中获得足够的收入或支持。这就导致了两个潜在的问题:

  1. 开发者维护压力大:个人开发者在面对成千上万用户的需求时,往往难以承担更新和维护的压力。他们没有足够的时间和资源去修复问题或引入新功能,这可能导致库长期得不到维护。这种状况不仅让依赖这些库的开发者处于被动地位,也让整个项目的稳定性面临风险。

  2. 维护者缺乏激励:许多开源项目的开发者并没有从他们的劳动中获得经济回报,当他们觉得自己的付出得不到应有的认可时,可能会选择放弃维护。这就让那些依赖这些库的项目处于危险之中,尤其是在需要快速响应的情况下。开源项目需要开发者的热情和动力,但如果缺乏有效的激励机制,这种热情往往难以持久。

更糟糕的是,这些开源库常常是整个前端生态中不可或缺的一部分。大公司将它们纳入自己的项目,而不一定会对其进行额外的测试或二次开发,导致对这些库的依赖一旦出现问题,就会对整个系统造成严重的影响。维护者在个人时间、资源和激励不足的情况下,很难对社区的庞大需求做出及时的响应,进一步加剧了这种不可控性。

NPM 的问题:依赖地狱与不可控性

NPM 生态虽然给开发者带来了极大的便利,但也伴随着一些深层次的问题:

  1. 过度依赖第三方包:很多时候,开发者会为了图方便而直接使用现成的库,即使它的功能实现非常简单。这不仅增加了项目的复杂性,还可能引入额外的安全隐患。一个简单的字符串补全工具,可能成为数千个项目的依赖,这种现象不仅增加了项目的重量,还使得项目的稳定性更加脆弱。

  2. 不可控的依赖链:NPM 中每个包都有可能依赖多个其他包,这些依赖又会再继续依赖下去,形成错综复杂的依赖链。这些依赖链中的任意一个包的更新、弃用或删除,都会影响整个项目的稳定性。这就像是一个庞大的多米诺骨牌,一旦有一个节点出现问题,整条依赖链都可能会受到冲击。开发者往往难以掌握这些复杂的依赖链,导致问题出现时束手无策。

  3. 版本管理的混乱:虽然语义化版本控制是前端社区的一个标准,但许多开发者在发布版本时并没有严格遵守这一规范,导致版本间的不兼容性成为常态。加之 "^" 或 "~" 号的使用,使得我们的依赖更新不再受自己控制。版本的不一致性往往会导致无法预料的问题,尤其是在某些库自动升级时,可能会引入新的 bug 或与其他依赖产生冲突。

如何避免依赖陷阱:减少依赖、重视模块设计

要避免依赖陷阱,我们需要对依赖进行更严格的管理,并重视模块的设计与代码的可控性:

  1. 减少不必要的依赖:在引入第三方库之前,应该首先考虑该功能是否可以自己实现。如果功能简单,自己编写代码通常比引入一个依赖更为稳妥。这样不仅可以减少对外部模块的依赖,还可以更好地掌控代码的质量和安全性。

  2. 管理依赖版本:尽量锁定依赖的具体版本,避免使用模糊版本号,以减少潜在的不兼容问题。同时可以利用工具(如 npm-shrinkwrap 或 yarn.lock)来管理依赖树,确保依赖的版本一致性和可控性。这种方式可以有效降低因为上游版本变动而带来的风险。

  3. 建立更好的依赖审查机制:公司和团队应当对项目中的依赖进行定期审查,尤其是对那些长期没有更新或维护的库要格外关注。可以考虑用自动化工具来扫描依赖的安全漏洞和更新状态,以便及时采取措施来替换不再可靠的依赖。

  4. 训练好的模型,敢于造轮子:由人来做重复的工作往往是被嫌弃的,都想最大程度的减少重复。但这在无形中增大了耦合度,或许让大模型来造轮子,是个更好的选择

总结

前端项目中的依赖管理问题需要引起更多开发者的重视。通过 "left_pad" 事件以及最近个站因 CDN 包被删除而崩溃的案例,我们应该意识到依赖管理中的风险与隐患。减少不必要的依赖、重视模块设计、合理管理版本,是提升前端项目稳定性的重要手段。同时,我们也应当关注开源库的所有权和维护问题,支持那些为社区作出贡献的开发者,让开源生态变得更加健康和可持续。
训练大模型,让它来造轮子,是一个持续正反馈的过程,也是值得做的,你觉得呢?

相关文章
|
2天前
node环境之当我们遇到需要付费的依赖库@fortawesome/fontawesome-pro导致npm install无法进行怎么办-fontawesome-pro依赖库
node环境之当我们遇到需要付费的依赖库@fortawesome/fontawesome-pro导致npm install无法进行怎么办-fontawesome-pro依赖库
node环境之当我们遇到需要付费的依赖库@fortawesome/fontawesome-pro导致npm install无法进行怎么办-fontawesome-pro依赖库
|
5月前
|
缓存 资源调度 持续交付
在清空NPM缓存后,检查是否所有依赖都已正确安装
在清空NPM缓存后,检查是否所有依赖都已正确安装
|
5月前
|
前端开发 搜索推荐 开发者
揭秘Web前端的隐形英雄:神奇的title与alt属性,你真的了解吗?
【8月更文挑战第26天】在Web开发中,`title`和`alt`属性对于提升网站的可访问性和搜索引擎优化至关重要。`title`属性可在鼠标悬停时显示额外信息,增强用户体验;`alt`属性主要用于图像,提供替代文本以确保视觉障碍用户及搜索引擎能理解图像内容。正确使用这两个属性可以显著提高网站的友好性和可达性。
124 0
|
3月前
|
缓存 资源调度 持续交付
在清空NPM缓存后,我如何检查是否所有依赖都已正确安装?
【10月更文挑战第5天】在清空NPM缓存后,我如何检查是否所有依赖都已正确安装?
|
3月前
|
缓存 JavaScript 前端开发
拿下奇怪的前端报错(三):npm install卡住了一个钟- 从原理搞定安装的全链路问题
本文详细分析了 `npm install` 过程中可能出现的卡顿问题及解决方法,包括网络问题、Node.js 版本不兼容、缓存问题、权限问题、包冲突、过时的 npm 版本、系统资源不足和脚本问题等,并提供了相应的解决策略。同时,还介绍了开启全部日志、使用替代工具和使用 Docker 提供 Node 环境等其他处理方法。
1765 0
|
3月前
|
前端开发 JavaScript 开发工具
从零开始:构建、打包并上传个人前端组件库至私有npm仓库的完整指南
从零开始:构建、打包并上传个人前端组件库至私有npm仓库的完整指南
489 0
|
3月前
|
资源调度 前端开发 安全
前端实战:基于Verdaccio搭建私有npm仓库,轻松上传与下载自定义npm插件包
前端实战:基于Verdaccio搭建私有npm仓库,轻松上传与下载自定义npm插件包
164 0
|
5月前
|
缓存 资源调度 持续交付
在清空NPM缓存后,如何检查是否所有依赖都已正确安装
在清空NPM缓存后,如何检查是否所有依赖都已正确安装
|
5月前
|
API Java Python
API的神秘面纱:从零开始构建你的RESTful服务
【8月更文挑战第31天】在现代网络应用开发中,RESTful API已成为数据交互的标准。本文通过比较流行的技术栈(如Node.js、Python的Django和Flask、Java的Spring Boot)及其框架,帮助你理解构建RESTful API的关键差异,涵盖性能、可扩展性、开发效率、社区支持、安全性和维护性等方面,并提供示例代码和最佳实践,指导你选择最适合项目需求的工具,构建高效、安全且易维护的API服务。
66 0
|
5月前
|
存储 安全 Java
阿里云云效产品使用合集之怎么设置使用npm私有仓库进行流水线拉取依赖
云效作为一款全面覆盖研发全生命周期管理的云端效能平台,致力于帮助企业实现高效协同、敏捷研发和持续交付。本合集收集整理了用户在使用云效过程中遇到的常见问题,问题涉及项目创建与管理、需求规划与迭代、代码托管与版本控制、自动化测试、持续集成与发布等方面。

推荐镜像

更多