paint-brush
微前端迁移之旅 - 第 1 部分:设计经过@isharafeev
1,323 讀數
1,323 讀數

微前端迁移之旅 - 第 1 部分:设计

经过 Ildar Sharafeev13m2023/07/12
Read on Terminal Reader

太長; 讀書

迁移到微前端架构需要在组织结构和运营基础方面进行大量投资。最好从利用延迟加载(动态导入)的分布式整体架构开始。迫切需要将代码库划分为由不同团队控制的不同所有权领域。
featured image - 微前端迁移之旅 - 第 1 部分:设计
Ildar Sharafeev HackerNoon profile picture

在当今快节奏的数字世界中,敏捷性和可扩展性至关重要,企业不断寻求提高 Web 应用程序性能和可维护性的方法。


实现这些目标的一种流行方法是从整体架构迁移到分布式架构(或微前端)。本系列文章“微前端迁移之旅”分享了我在 AWS 期间进行此类迁移的个人经历。


免责声明:在开始之前,需要注意的是,虽然本文分享了我的个人经验,但我无法披露 AWS 或任何其他组织的工具、技术或特定流程的任何专有或内部细节。


我致力于尊重法律义务,并确保本文仅关注微前端迁移过程中涉及的一般概念和策略。


目的是提供可适用于更广泛背景的见解和经验教训,而不泄露任何机密信息。

移民动机

我从 Martin Fowler 博客上的文章中了解了微前端(我想你们很多人也一样)。它提出了以与框架无关的方式构建微前端架构的不同方法。


当我深入研究这个主题时,我意识到我们现有的整体架构正在成为我们团队生产力的重大瓶颈,并阻碍我们应用程序的整体性能。


促使我考虑迁移的关键因素之一是我们的应用程序的包大小不断增加。


在 2020 年夏天进行彻底的捆绑包分析后,我发现自 2019 年初首次推出以来,捆绑包大小(gzip 压缩)已从 450KB 增长到 800KB(解析后几乎为 4MB)——几乎是原始大小的两倍。


考虑到我们服务的成功并预测其持续增长,很明显这种趋势将持续下去,进一步影响我们应用程序的性能和可维护性。


虽然我对微前端的概念充满热情,但我也认识到,由于我们面临的具体挑战,我们还没有准备好采用它们:


  1. 组织结构小:在我分析时,我们的组织相对较小,我是团队中唯一的全职前端工程师。迁移到微前端架构需要在组织结构和运营基础方面进行大量投资。


    拥有一个成熟的结构来有效处理分布式架构并反映不同前端组件之间的依赖关系至关重要。


  2. 有限的业务领域:虽然微前端可以根据有界上下文和业务功能进行拆分(在“微前端架构中的领域驱动设计”帖子中了解更多信息),但我们的核心业务领域还不够广泛,不足以证明完全解耦为多个微前端。然而,应用程序内存在明显的边界,这对于开辟并过渡到分布式架构是有意义的。


考虑到这些因素,我意识到循序渐进的方法是必要的。我的目标不是完全迁移到微前端,而是确定应用程序中可以从分布式架构中受益的特定区域。


这将使我们能够解决性能和可扩展性问题,而不会破坏整体组织结构或损害我们业务领域的完整性。它还会给我们一些时间来发展团队并观察业务方向。


请注意,如果您只想通过使用 mciro-frontend 架构来解决应用程序的性能(捆绑包大小)问题,这可能不是最好的主意。最好从利用延迟加载(动态导入)的分布式整体架构开始。


此外,我认为它会比微前端架构更优雅地处理包大小问题,因为微前端架构很可能有一些共享代码不会被分成供应商块,并且它将被构建到应用程序包中(这是这种分布式架构的缺点之一——您需要在共享内容、共享时间和共享方式之间进行权衡)。


然而,分布式整体架构的扩展性不如微前端。当您的组织快速发展时,您的团队也可能会以同样的速度发展。


迫切需要将代码库划分为由不同团队控制的不同所有权领域。


每个团队都需要有自己独立于其他团队的发布周期,如果他们的代码库纯粹专注于他们的领域,并且会快速构建(代码隔离 -> 更好的可维护性/需要维护和维护的代码更少,每个团队都会感激不已)构建 -> 更好的可测试性/更少的维护和执行测试)。

开始

为了获得领导层的支持,我制作了一份有说服力的技术愿景文件,其中包含全面的性能分析,包括网络重要指标,并概述了向分布式前端迁移的各个阶段。


此迁移的中间阶段之一是建立分布式整体架构,其中可以通过延迟加载技术异步交付多个模块/小部件,同时利用核心服务和小部件之间的共享基础设施,例如 S3 存储桶和 CDN 。


正如我在上一篇文章中概述的那样,此类文档的主要思想是描述目标实现并解决最大问题后您希望的未来。这不是执行计划的问题!


差不多一年后,我的微前端迁移计划终于到了付诸实施的时候了。随着即将扩展到新领域和我们拥有更大的团队,我们已经做好了执行迁移的准备。


这感觉就像一个千载难逢的机会,我们不能错过。


毕竟,继续局限于整体架构意味着永远要克服其局限性。


扩展到新领域的有限时间起到了催化剂的作用,推动我们立即构建一个更具可扩展性和可维护性的架构,而不是进行短暂而缓慢的迭代!


为了执行迁移并同时处理新领域中的工作,我们将团队分为两个专门小组。功能工作具有更高的优先级,需要更多的资源,并且需要以更快的速度迭代。


为了确保迁移过程的完整性和全面理解,分配一个专门的小型团队专门负责处理迁移是有意义的。


然而,如果不首先确保微前端概念被证明是成功的,我们就无法继续进行功能工作。


为了降低风险并提供清晰的路线图,创建包含精确估计和彻底风险评估的低级设计文档至关重要。本文档作为蓝图,概述了迁移的必要步骤和注意事项。


这一过程的关键里程碑是概念验证的开发,该概念验证将证明所有组件根据设计成功集成。


这一里程碑被恰当地称为“不归路”,旨在验证微前端架构的可行性和有效性。


虽然我对迁移的成功感到乐观,但为突发事件做好准备也很重要。因此,我设计了一个 B 计划,作为备用策略,以防最初的概念没有产生预期的结果。


这包括在估算中额外分配 7 天的时间,专门让我在枕头上哭泣,再加上几天的时间,让一个新的功能模块条目通过延迟加载连接到核心(还记得分布式整体架构吗?)。

该设计

在设计微前端时,通常有 3 种组合方法,每种方法都侧重于运行时应用程序解析发生的位置。这些方法的优点在于它们并不相互排斥,并且可以根据需要进行组合。

服务器端组成

基本思想是利用反向代理服务器来分割每个页面的微前端包,并根据路由 URL 进行硬页面重新加载。

优点:

  • 实施简单


缺点:

  • 全局状态不会在微前端应用程序之间同步。这对我们来说显然是一个禁忌点,因为我们在客户端执行长时间运行的后台操作。


    您可能会争辩说,我们可以将该操作的“队列”的快照保留到本地存储,并在硬重载后从中读取,但由于安全原因,我们无法实现这一点。


    这只是全局状态的一个示例,但这里是它的外观的另一个示例:侧导航面板的状态(展开/折叠)、Toast 消息等。


  • 跨微应用程序导航时的硬刷新对客户来说不太友好。有一种方法可以使用 Service Worker 来缓存共享 HTML,但维护起来会更加复杂。


  • 基础设施的额外运营和维护成本:每个微前端应用程序的代理服务器(如果直接从 CDN 读取,可以避免这种情况),单独的基础设施以部署公共(供应商)依赖项以供多个页面重用,并正确地使用由浏览器缓存。

边侧合成

微前端组合的另一种方法是边缘侧组合,它涉及在边缘层组合微前端,例如 CDN。例如,Amazon CloudFront 支持Lambda@Edge集成,从而允许使用共享 CDN 来读取和提供微前端内容。

优点:

  • 需要维护的基础设施更少:无需代理服务器,每个微应用都有单独的 CDN


  • 使用无服务器技术实现几乎无限的扩展


  • 与独立代理服务器相比,延迟更好


缺点:

  • 冷启动时间可能成为一个问题


  • 如果您需要拥有多区域(隔离)基础设施,则并非所有 AWS 区域都支持 Lambda@Edge

客户端组成

客户端组合是微前端架构的另一种方法,它利用客户端微前端编排技术,与服务器实现解耦。


该架构中的关键角色是容器(shell)应用程序,它具有以下职责:


  • 解决横切问题:容器应用程序处理集中的应用程序布局、站点导航、页脚和帮助面板。通过事件总线与具有横切关注点的微前端集成,其中合成事件在全局窗口范围内发送和处理。


  • 微前端的编排:容器应用程序根据应用程序的要求和用户交互确定加载哪个微前端包以及何时加载。


  • 组合全局依赖项:容器应用程序组合所有全局依赖项,例如 React、SDK 和 UI 库,并将它们公开为可以在微前端之间共享的单独包 (vendor.js)。


总体思路是每个微前端包都会生成两种类型的资源文件:

  • {hash}/index.js:它作为微前端应用程序的入口点,哈希代表整个构建的唯一标识符。


    该哈希充当 S3 存储桶中每个包的前缀键。需要注意的是,可能存在多个入口点,但所有入口点的哈希值保持相同。


  • manifest.json:这是一个清单文件,其中包含微前端应用程序的所有入口点的路径。该文件将始终保留在 S3 存储桶的根目录中,因此容器能够轻松发现它。


    我建议在 S3 存储桶中打开此文件的版本控制,以便更好地观察更改。如果您使用 Webpack 构建项目,我强烈推荐WebpackManifestPlugin ,它会为您完成所有繁重的工作。


容器仅根据阶段和区域感知微前端资产源域 URL(CDN 源)。在初始页面加载期间,容器会下载每个微前端应用程序的清单文件。


清单文件的大小很小(约 100 字节),以避免影响页面加载时间,并且即使在一个容器中聚合多个微前端时也能很好地扩展。将清单文件视为浏览器缓存存储中的不可变性至关重要,以防止过度缓存。


选择正确的编排库是本文中最大的挑战,将在下一章中讨论。

优点:

  • 与服务器实现无关:这种方法可以在没有任何特定服务器要求的情况下实现,从而为所使用的后端技术提供了灵活性。如上图所示,你甚至可以没有任何服务器


  • 保留全局状态:通过使用容器(shell)应用程序,可以在微前端之间切换时维护全局状态。这确保了无缝的用户体验并避免在转换期间丢失上下文。


  • 去中心化方法:每个微前端都可以独立决定将哪些数据发送到浏览器以引导自身。容器应用程序只需遵循明确定义的合同,即可实现更大的自主性和模块化。


  • 简单的本地设置:可以根据开发需求在生产 URL 和本地 URL 之间轻松调整资产源。清单文件帮助容器应用程序发现并加载所需的微前端。开发人员可以专注于仅运行容器和他们正在处理的特定微前端。


缺点:

  • 更多网络跃点来获取清单文件:由于容器需要检索每个微前端的清单文件,因此与其他组合方法相比,可能会存在额外的网络请求和潜在的延迟。这可以通过在初始页面加载时预先加载所有清单或引入一些预加载技术来缓解。


  • 遵守通用合同:每个微前端都需要遵守生产构建的通用合同。这可以通过共享配置和标准化开发实践来促进,以确保微前端的一致性(以下部分将详细介绍这一点)。

混合成分

正如我在本章前面提到的,所有这些组合模式都可以在同一个 shell 应用程序中混合和匹配。下面是它的示例:

推荐

我建议从一开始就采用同质方法——选择一种更适合您的组合模式,并开始围绕它构建基础设施。


对于我们来说,客户端组合是最好的选择,但对于未来,我们考虑将某些区域切换到边缘侧编排(基于 Lambda@Edge 的可用性)。

选择编排库

当谈到在微前端架构中实现客户端组合时,选择正确的编排库是一个关键的决定。


所选库将在管理容器应用程序内微前端的动态加载和协调方面发挥至关重要的作用。


存在几个流行的编排库,每个库都有自己的优点和注意事项。

单水疗中心

Single-spa是一种广泛采用的编排库,为微前端组合提供了灵活且可扩展的方法。它允许开发人员创建一个 shell 应用程序来协调多个微前端的加载和卸载。


Single-SPA 提供对生命周期事件的细粒度控制,并支持不同的框架和技术。


优点:

  • 与框架无关:库可以与各种前端框架很好地配合,例如 React、Angular、Vue.js 等。


  • 灵活的配置:它为路由、延迟加载和共享依赖项提供了强大的配置选项。


  • 强大的生态系统:Single-SPA 拥有活跃的社区以及丰富的插件和扩展生态系统。


缺点:

  • 学习曲线:开始使用 single-spa 可能需要对其概念和 API 进行一些初步学习和理解。


  • 定制复杂性:随着微前端架构的复杂性不断增加,配置和管理编排可能变得具有挑战性。

乾坤

乾坤是蚂蚁金服(阿里巴巴)团队开发的一个强大的编排库。它使用部分 HTML 方法进行组合。在微前端应用程序方面,它会生成一个纯 HTML 片段,其中包含要加载的所有入口点。


使用此 HTML 文件后,容器会执行所有编排并安装应用程序。在此配置中,部分 HTML 扮演了我在上一章中讨论过的清单文件的角色。


优点:

  • 与框架无关:Qiankun支持各种前端框架,包括React、Vue.js、Angular等。


  • 简化集成:乾坤提供了一套易于使用的API和工具来创建和管理微前端。


  • 可扩展性和性能:乾坤为代码沙箱、状态隔离和微前端之间的通信提供了有效的机制。


缺点:

  • 依赖关系冲突:管理共享依赖关系并确保微前端之间的兼容性可能需要仔细配置和考虑。


  • 学习曲线:虽然乾坤提供了大量文档,但采用新库可能会给您的开发团队带来学习曲线。


  • 通过线路发送的冗余数据:部分 HTML 片段包含需要通过网络发送的冗余数据(正文、元、DOCTYPE 标记)。

模块联盟

Module Federation是 Webpack 提供的一项功能,在 Web 开发社区中获得了极大的关注和炒作。该技术允许开发人员在运行时在多个应用程序之间共享代码,使其成为构建微前端的有吸引力的选择。


凭借与 Webpack 的无缝集成和运行时灵活性,Module Federation 已成为管理和编排微前端的流行选择。


优点:

  • 与 Webpack 无缝集成:如果您已经使用 Webpack 作为构建工具,那么利用 Module Federation 可以简化设置和集成过程。


  • 运行时灵活性:模块联合支持动态加载和共享依赖项,从而提供管理微前端的灵活性。


缺点:

  • 有限的框架支持:虽然模块联合与多个前端框架兼容,但它可能需要针对特定用例进行额外的配置或解决方法。


  • 社区支持:Module Federation 是一项相对较新的技术,在 Webpack 5 中作为核心插件发布(后来向后移植到v4 )。 Next.js 库也较新,最近作为开源版本发布。与所有新工具一样,社区可能较小,可用的支持也较少。如果您的截止日期很紧或预计会遇到没有现成答案的问题,那么考虑这个因素很重要。

结论

在“微前端迁移之旅”系列的第一部分中,我们讨论了从 Web 整体迁移到分布式架构背后的动机,以及向领导层推销该想法所采取的初步步骤。


我们探讨了技术愿景文档的重要性,该文档展示了详细的性能分析并概述了迁移的不同阶段。


然后,我们深入研究了微前端的设计注意事项,讨论了三种方法:服务器端组合、边缘端组合和客户端组合。


每种方法都有其优点和缺点,选择取决于各种因素,例如全局状态的同步、客户体验、基础设施复杂性和缓存。


此外,我们还探索了流行的编排库,例如 single-spa、qiankun 和 Module Federation,重点介绍了它们的功能、优点和潜在挑战。


与我一起阅读本系列的下一部分,我们将继续我们的微前端迁移之旅,并在此过程中发现更多有趣且有价值的见解!


最初于 2023 年 4 月 18 日发布于https://thesametech.com


您还可以在 Twitter 上关注我在 LinkedIn 上连接以获取有关新帖子的通知!