网上开店系统Wix如何将微前端提升到一个新的水平? - Shaha


微前端的概念已经存在很长一段时间了。自 2013 年左右以来,我们一直在 Wix 中使用这种架构,甚至早在它被赋予这个名字之前。这也是我们在 2016 年从 AngularJS 逐步迁移到 React 的关键因素。多年来,我们一直在发展它并收集大量经验。在本文中,我想分享我们为发展开发大规模微前端的概念所做的一些事情(在撰写本文时,我们有 700 名开发人员致力于此架构)。
 
微前端简介
有 很多关于微前端的文章,本文试图关注更高级的主题,所以我会尽量使介绍非常简短。当一个团队变得非常大时,许多人开始开发一个单体应用程序变得非常困难:

  • 代码库变得非常大,难以维护并且充满了不必要的复杂性。
  • 构建变得很长,并且涉及许多移动部件,大多数开发人员不知道在出现问题时如何处理。
  • 部署包含太多更改,这意味着完全不相关的更改可能会阻止人们部署或强制回滚版本。
  • 名单还在继续。Monoliths 在大团队中很难维护,如果你在这里,我想你知道这一点。

这就是为什么在大团队中,尝试将应用程序分解为更小的独立事物是一个好主意,这些事物可以在单独的项目中开发,单独构建和彼此分开部署。我一直强调,这对于大型团队来说是一种明智的方式。如果你有一个小团队,不要这样做,它只会让你的生活更艰难。在 Wix 中,只有当我们有大约 100 名开发人员在开发前端应用程序时,我们才开始使用这种方法。
我见过的演示这种方法的最简单的例子是这样的:
<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>

所以,我们这里有三个独立的包。每个都可以单独开发、构建和部署,每个都注册一个自定义元素,父应用程序最终可以呈现该元素。不要误会我的意思,您不必使用自定义元素来拥有微前端架构;这些包可以将 React 组件注册到父应用程序使用的某个全局 Map 以便在渲染时引用它们(这实际上是我们在 Wix 所做的),但是自定义元素示例是一种很酷的方式来展示它而无需去进入这些细节。
 
Wix 的微前端
我将深入探讨我们多年来构建的内部架构和工具的许多细节,所以我想花点时间快速了解一下 Wix 平台,别担心你不必了解很多关于 Wix 的信息。
Wix 是一个平台,人们可以使用 WYSIWYG 编辑器为其业务创建站点,并使用各种业务管理工具管理业务。这意味着,例如,企业主可以创建一个带有在线商店的站点,他们的客户可以在其中将商品添加到购物车、查看购物车、结帐、查看订单状态等,所有这些都可以通过完全可定制的站点进行。另一方面,企业主可以在 Wix 上管理商店,这意味着他们有管理页面,可以在其中编辑目录、查看订单和分析、浏览客户和管理库存;所有这些都在一个调用业务管理的大应用程序中。
但它并不止于此,网站还可以有博客、论坛和注册/登录屏幕,或者它们可以是可以订购食物或预订餐桌的餐厅网站,或者它们可以是会议或音乐会的网站人们可以在那里购买门票并选择他们想坐的地方,甚至可以从网站内在线观看。在业务管理方面,企业主还可以向客户发送时事通讯、管理其业务的在线活动、创建自动化(例如,在交付后 5 天向客户发送反馈电子邮件),甚至与当前在其网站上的人聊天。
你得到了图片。网站和业务管理都有大量功能。这就是为什么我们决定呈现所有站点的查看器和业务管理都将是微前端主机。在本文中,我们将重点介绍这两个平台及其不同的需求。
老实说,我们实际上在 Wix 中还有两个微前端主机,它们是编辑器(所有站点都在其中创建)和我们的移动应用程序(我所知道的世界上唯一的微前端 React Native 应用程序))。但是,每一个都值得拥有自己的文章,因此我们不会在本文中触及它们。
  • 简而言之,在业务管理器中运行的微前端可以是托管在侧边栏旁边的完整页面体验,或者添加到顶部栏中的小部件,或者托管在不同微前端内的小部件。
  • 简而言之,查看器将编辑器创建的大 json 转换为动态 React 组件树,其中每个组件都取自拥有它的微前端,并传递设置和设计参数,这些设置和设计参数也存储在那个json。

 
可插拔微前端
让我们讨论我们在开发查看器和业务管理器时遇到的第一个挑战。与许多应用程序的功能是预先确定的不同,我们的应用程序根据上下文加载了完全不同的功能集:

  • 每个企业都安装了不同的扩展程序,每个扩展程序都可以在业务管理器侧边栏和路由器中注册一个页面,以便用户可以导航到它。
  • 每个扩展还可以注册其他类型的业务组件,例如显示您在屏幕截图业务管理器 (3) 中看到的特定联系人信息的选项卡。
  • 站点中的每个页面都有用户在编辑页面时放置的不同小部件,并且每个小部件在 DOM 树中的位置可能不同,具体取决于用户附加小部件的父级。

这些不是 Wix 的特殊要求。这些是可插拔系统非常经典的特征,这正是我们为解决这些问题而创建的。此外,微前端是可插拔系统的经典解决方案,是我们解决方案的重要组成部分。让我们讨论可插拔微前端的构建块是什么。
首先,我们需要有一个地方来存储有关现有扩展、页面和小部件的所有信息。例如,我们需要知道电子商务 扩展包括应该出现在业务管理器中的产品管理器和订单管理器页面,并且每个页面在业务管理器中都有一个专用的侧边栏条目和路由。
另外,电子商务扩展包括订单,其应显示在与一些标签标题接触视图接触标签。
最后,电子商务 扩展包括产品库、产品和购物车用户可以在网站的某些页面上放置的小部件。
那么我们将所有这些信息存储在哪里呢?我们有一项称为开发中心的服务,Wix 中的每个开发人员都可以在其中定义一个新的扩展。一个扩展可以有多个组件,每个这样的组件可以是不同的类型和与此类型相关的数据。因此,如果我们以电子商务扩展程序为例,它包括以下组件:
  1. 产品管理。类型:业务管理页面。数据:捆绑 URL、侧边栏标签、路由路径。
  2. 订单管理。类型:业务管理页面。数据:捆绑 URL、侧边栏标签、路由路径。
  3. 订单选项卡。类型:联系人选项卡。数据:捆绑 URL、标签标题
  4. 产品画廊小部件。类型:查看器小部件。Data : Bundle URL, 一堆编辑器相关的数据我们就不讲了。
  5. 产品小部件。类型:查看器小部件。Data : Bundle URL, 一堆编辑器相关的数据我们就不讲了。
  6. 购物车小部件。类型:查看器小部件。Data : Bundle URL, 一堆编辑器相关的数据我们就不讲了。

所以现在业务管理器渲染的时候,会经过如下流程:
  1. 检查此站点中安装了哪些扩展程序(我们有一项服务,可以记住每个站点中安装了哪些扩展程序,我们有一个应用程序市场,用户安装扩展程序,应用程序市场的所有元数据也存储在开发中心,但我们不会深入讨论)。
  2. 对于已安装的扩展,从业务管理器页面类型的开发中心获取所有组件的列表。
  3. 根据组件数据将所有链接动态添加到带有正确路由的侧边栏。
  4. 使用来自组件数据的路由动态配置 React Router,以便当用户导航到页面时,我们将动态导入可以呈现该页面的正确微前端组件的bundle url。

当业务管理器中的联系人管理器页面呈现时,会发生完全相同的过程,唯一的区别是它将查询类型为contact tabs 的组件。相反,它将根据组件数据将选项卡标题动态添加到选项卡选择器,类似于业务管理器主机在侧边栏中所做的操作。理论上,如果我们愿意,联系人选项卡的组件数据甚至可以包含一个路由,并且联系人页面也可以在主机的 React 路由器中配置一个嵌套路由。
查看器经历了类似的过程,但有一些细微的差别:
  1. 检查我们将要呈现的页面结构中需要哪些小部件(我们有一项提供有关页面结构信息的服务)。
  2. 对于那些小部件,从开发中心获取组件数据。
  3. 动态导入页面上所有小部件的bundle url,并根据页面结构呈现动态的React树。
  4. 在站点中的每个页面导航中重复该过程(请注意,在 Wix 中,站点的第一个导航是执行 SSR,站点内部的后续导航发生在客户端(如 SPA)中,因此该过程可以在客户端和服务器)。

最后,我们可以定义一个通用模式:一个可插拔的微前端主机需要找出它需要渲染的东西的bundle url是什么,它需要用安装的东西动态渲染它的UI,它需要在合适的时间下载正确的包时动态导入正确的包。除非确实有意义,否则不要急切地下载包非常重要,并且尽可能使用服务器端缓存优化这些流非常重要,否则性能会很快成为此类应用程序的瓶颈。
 
集成微前端
到目前为止,我们主要讨论了微前端提供由主机应用程序或其他微前端呈现的组件的情况。这是通过每个微前端在全局映射中注册其组件来完成的,该映射可用于主机和其他微前端,在这些微前端中,它们通过组件类型调用查找组件,如开发中心所述,以及它们的组件数据,可以用于在侧边栏中呈现链接、配置路由器等。
但是,如果某个微前端想要调用不同微前端中的某些功能怎么办?
使用模块注册表.
,,,
 
第三方微前端
Wix 是一个开放平台,这意味着我们希望能够为不在 Wix 工作的外部开发人员创建业务管理器页面和查看器小部件。也就是说,这仍然意味着我们需要牢记用户的安全性,这意味着外部微前端需要以“老派方式”工作,这意味着它们在 iframe 中被沙箱化。它的工作方式是我们有一个特殊的微前端业务管理器页面,它实际上可以托管外部开发页面的 iframe,并使用发布消息将所有业务管理器的 API 桥接到它。

结论
很明显,为了解决微前端引入的许多问题,我们做了很多工作,因为我们相信这个解决方案为处理大规模问题的团队提供了大量的速度和独立性。我们希望有一天能够公开发布其中一些工具,并相信很多人会发现它们很有用。我们创建的许多解决方案对于单体应用也非常有用,但毫无疑问,微前端是有成本的。
在过去的 2 年里,我们投入了大量资金来创建一个我们称之为 Falcon 的构建系统,我们相信它可以用于智能地构建非常大的单一存储库(是的,我们已经研究了 Bazel,但目前我们正在使用内部的出于本文讨论范围之外的原因的解决方案)。这对我们来说非常重要,因为即使在微前端世界中,我们也希望能够为每个扩展提供单一存储库,但它也将允许我们尝试替代解决方案,将一个巨大的东西作为一个整体构建和部署.
我并不是说我们放弃了微前端,我认为不要完全迷恋一种解决方案并尝试看看其他方法是否可行,这一点非常重要。
我从整篇文章中最重要的收获是,解决如此众多的基础设施挑战是一次令人难以置信的经历,而这些挑战只有生活在这些技术前沿的工程组织才能解决,我相信我们未来还会面临更多此类挑战。