前端架构思考:代码复用带来的隐形耦合,可能让大模型造轮子是更好的选择-从 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 包被删除而崩溃的案例,我们应该意识到依赖管理中的风险与隐患。减少不必要的依赖、重视模块设计、合理管理版本,是提升前端项目稳定性的重要手段。同时,我们也应当关注开源库的所有权和维护问题,支持那些为社区作出贡献的开发者,让开源生态变得更加健康和可持续。
训练大模型,让它来造轮子,是一个持续正反馈的过程,也是值得做的,你觉得呢?

相关实践学习
Serverless极速搭建Hexo博客
本场景介绍如何使用阿里云函数计算服务命令行工具快速搭建一个Hexo博客。
相关文章
|
2月前
|
人工智能 测试技术 数据处理
首个Mamba+Transformer混合架构多模态大模型来了,实现单卡千图推理
【10月更文挑战第18天】《LongLLaVA: Scaling Multi-modal LLMs to 1000 Images Efficiently via Hybrid Architecture》提出了一种新型多模态大模型LongLLaVA,结合了Mamba和Transformer架构,通过系统优化实现在单张A100 80GB GPU上处理近千张图像的突破。该模型在视频理解、高分辨率图像分析和多模态智能体任务中表现出色,显著提升了计算效率。
159 64
|
2月前
|
人工智能 前端开发 JavaScript
前端架构思考 :专注于多框架的并存可能并不是唯一的方向 — 探讨大模型时代前端的分层式微前端架构
随着前端技术的发展,微前端架构成为应对复杂大型应用的流行方案,允许多个团队使用不同技术栈并将其模块化集成。然而,这种设计在高交互性需求的应用中存在局限,如音视频处理、AI集成等。本文探讨了传统微前端架构的不足,并提出了一种新的分层式微前端架构,通过展示层与业务层的分离及基于功能的横向拆分,以更好地适应现代前端需求。
|
25天前
|
消息中间件 供应链 架构师
微服务如何实现低耦合高内聚?架构师都在用的技巧!
本文介绍了微服务的拆分方法,重点讲解了“高内聚”和“低耦合”两个核心设计原则。高内聚强调每个微服务应专注于单一职责,减少代码修改范围,提高系统稳定性。低耦合则通过接口和消息队列实现服务间的解耦,确保各服务独立运作,提升系统的灵活性和可维护性。通过领域建模和事件通知机制,可以有效实现微服务的高效拆分和管理。
47 7
|
25天前
|
缓存 负载均衡 网络协议
高并发架构的CDN知识介绍
本文详细介绍了网络请求过程,特别是大型网站架构中DNS和CDN的作用。通过一张常用架构图,文章解释了从客户端请求到服务器响应的全过程,包括DNS解析、负载均衡、CDN加速等关键环节,帮助读者深入了解高并发架构的设计原理和优化方法。
70 1
|
2月前
|
前端开发 JavaScript API
2025年前端框架是该选vue还是react?有了大模型-例如通义灵码辅助编码,就不用纠结了!vue用的多选react,react用的多选vue
本文比较了Vue和React两大前端框架,从状态管理、数据流、依赖注入、组件管理等方面进行了详细对比。当前版本和下载量数据显示React更为流行,但Vue在国内用户量增长迅速。Vue 3通过组合式API提供了更灵活的状态管理和组件逻辑复用,适合中小型项目;React则更适合大型项目和复杂交互逻辑。文章还给出了选型建议,强调了多框架学习的重要性,认为技术问题已不再是选型的关键,熟悉各框架的最佳实践更为重要。
|
2月前
|
缓存 JavaScript 前端开发
拿下奇怪的前端报错(三):npm install卡住了一个钟- 从原理搞定安装的全链路问题
本文详细分析了 `npm install` 过程中可能出现的卡顿问题及解决方法,包括网络问题、Node.js 版本不兼容、缓存问题、权限问题、包冲突、过时的 npm 版本、系统资源不足和脚本问题等,并提供了相应的解决策略。同时,还介绍了开启全部日志、使用替代工具和使用 Docker 提供 Node 环境等其他处理方法。
723 0
|
2月前
|
前端开发 JavaScript 开发工具
从零开始:构建、打包并上传个人前端组件库至私有npm仓库的完整指南
从零开始:构建、打包并上传个人前端组件库至私有npm仓库的完整指南
315 0
|
23天前
|
缓存 负载均衡 JavaScript
探索微服务架构下的API网关模式
【10月更文挑战第37天】在微服务架构的海洋中,API网关犹如一座灯塔,指引着服务的航向。它不仅是客户端请求的集散地,更是后端微服务的守门人。本文将深入探讨API网关的设计哲学、核心功能以及它在微服务生态中扮演的角色,同时通过实际代码示例,揭示如何实现一个高效、可靠的API网关。
|
4天前
|
弹性计算 API 持续交付
后端服务架构的微服务化转型
本文旨在探讨后端服务从单体架构向微服务架构转型的过程,分析微服务架构的优势和面临的挑战。文章首先介绍单体架构的局限性,然后详细阐述微服务架构的核心概念及其在现代软件开发中的应用。通过对比两种架构,指出微服务化转型的必要性和实施策略。最后,讨论了微服务架构实施过程中可能遇到的问题及解决方案。
|
21天前
|
Cloud Native 安全 数据安全/隐私保护
云原生架构下的微服务治理与挑战####
随着云计算技术的飞速发展,云原生架构以其高效、灵活、可扩展的特性成为现代企业IT架构的首选。本文聚焦于云原生环境下的微服务治理问题,探讨其在促进业务敏捷性的同时所面临的挑战及应对策略。通过分析微服务拆分、服务间通信、故障隔离与恢复等关键环节,本文旨在为读者提供一个关于如何在云原生环境中有效实施微服务治理的全面视角,助力企业在数字化转型的道路上稳健前行。 ####

推荐镜像

更多