微前端的概念已经存在很长一段时间了。自 2013 年左右以来,我们一直在 Wix 中使用这种架构,甚至早在它被赋予这个名字之前。这也是我们在 2016 年从 AngularJS 逐步迁移到 React 的关键因素。多年来,我们一直在发展它并收集大量经验。在本文中,我想分享我们为发展开发大规模微前端的概念所做的一些事情(在撰写本文时,我们有 700 名开发人员致力于此架构)。 微前端简介 有 很多关于微前端的文章,本文试图关注更高级的主题,所以我会尽量使介绍非常简短。当一个团队变得非常大时,许多人开始开发一个单体应用程序变得非常困难:
- 代码库变得非常大,难以维护并且充满了不必要的复杂性。
- 构建变得很长,并且涉及许多移动部件,大多数开发人员不知道在出现问题时如何处理。
- 部署包含太多更改,这意味着完全不相关的更改可能会阻止人们部署或强制回滚版本。
- 名单还在继续。Monoliths 在大团队中很难维护,如果你在这里,我想你知道这一点。
<html> <head> <script src="https://shipping.example.com/shipping-service.js"></script> <script src="https://profile.example.com/profile-service.js"></script> <script src="https://billing.example.com/billing-service.js"></script> <title>Parent Application</title> </head> <body> <shipping-service /> <profile-service /> <billing-service /> </body> </html> |
- 简而言之,在业务管理器中运行的微前端可以是托管在侧边栏旁边的完整页面体验,或者添加到顶部栏中的小部件,或者托管在不同微前端内的小部件。
- 简而言之,查看器将编辑器创建的大 json 转换为动态 React 组件树,其中每个组件都取自拥有它的微前端,并传递设置和设计参数,这些设置和设计参数也存储在那个json。
可插拔微前端 让我们讨论我们在开发查看器和业务管理器时遇到的第一个挑战。与许多应用程序的功能是预先确定的不同,我们的应用程序根据上下文加载了完全不同的功能集:
- 每个企业都安装了不同的扩展程序,每个扩展程序都可以在业务管理器侧边栏和路由器中注册一个页面,以便用户可以导航到它。
- 每个扩展还可以注册其他类型的业务组件,例如显示您在屏幕截图业务管理器 (3) 中看到的特定联系人信息的选项卡。
- 站点中的每个页面都有用户在编辑页面时放置的不同小部件,并且每个小部件在 DOM 树中的位置可能不同,具体取决于用户附加小部件的父级。
- 产品管理。类型:业务管理页面。数据:捆绑 URL、侧边栏标签、路由路径。
- 订单管理。类型:业务管理页面。数据:捆绑 URL、侧边栏标签、路由路径。
- 订单选项卡。类型:联系人选项卡。数据:捆绑 URL、标签标题
- 产品画廊小部件。类型:查看器小部件。Data : Bundle URL, 一堆编辑器相关的数据我们就不讲了。
- 产品小部件。类型:查看器小部件。Data : Bundle URL, 一堆编辑器相关的数据我们就不讲了。
- 购物车小部件。类型:查看器小部件。Data : Bundle URL, 一堆编辑器相关的数据我们就不讲了。
- 检查此站点中安装了哪些扩展程序(我们有一项服务,可以记住每个站点中安装了哪些扩展程序,我们有一个应用程序市场,用户安装扩展程序,应用程序市场的所有元数据也存储在开发中心,但我们不会深入讨论)。
- 对于已安装的扩展,从业务管理器页面类型的开发中心获取所有组件的列表。
- 根据组件数据将所有链接动态添加到带有正确路由的侧边栏。
- 使用来自组件数据的路由动态配置 React Router,以便当用户导航到页面时,我们将动态导入可以呈现该页面的正确微前端组件的bundle url。
- 检查我们将要呈现的页面结构中需要哪些小部件(我们有一项提供有关页面结构信息的服务)。
- 对于那些小部件,从开发中心获取组件数据。
- 动态导入页面上所有小部件的bundle url,并根据页面结构呈现动态的React树。
- 在站点中的每个页面导航中重复该过程(请注意,在 Wix 中,站点的第一个导航是执行 SSR,站点内部的后续导航发生在客户端(如 SPA)中,因此该过程可以在客户端和服务器)。
结论 很明显,为了解决微前端引入的许多问题,我们做了很多工作,因为我们相信这个解决方案为处理大规模问题的团队提供了大量的速度和独立性。我们希望有一天能够公开发布其中一些工具,并相信很多人会发现它们很有用。我们创建的许多解决方案对于单体应用也非常有用,但毫无疑问,微前端是有成本的。 在过去的 2 年里,我们投入了大量资金来创建一个我们称之为 Falcon 的构建系统,我们相信它可以用于智能地构建非常大的单一存储库(是的,我们已经研究了 Bazel,但目前我们正在使用内部的出于本文讨论范围之外的原因的解决方案)。这对我们来说非常重要,因为即使在微前端世界中,我们也希望能够为每个扩展提供单一存储库,但它也将允许我们尝试替代解决方案,将一个巨大的东西作为一个整体构建和部署. 我并不是说我们放弃了微前端,我认为不要完全迷恋一种解决方案并尝试看看其他方法是否可行,这一点非常重要。 我从整篇文章中最重要的收获是,解决如此众多的基础设施挑战是一次令人难以置信的经历,而这些挑战只有生活在这些技术前沿的工程组织才能解决,我相信我们未来还会面临更多此类挑战。