怎么做微前端(Micro Front end)?

大概在年初的时候,我发布一篇关于微前端架构的文章,收到很多反馈。这里我想大概再简单说一下如何在实际开发过程中选择微前端的架构。微前端架构发展到今天,其实已经比较成熟,虽然还有一些问题要解决。我身边的朋友以及公司,都在努力解决目前存在的问题。但是作为一名架构师,我们如何去选择适合自己业务或者公司部门的微前端架构呢?

一般我们做软件架构选择的时候,大部分时候我们关注至少三个方面,

  • 业务需求
  • 组织结构
  • 开发人员的经验

搞清楚这些之后,我们开始选择实现微前端的具体过程。微前端有很多方法可以实现,那我们怎么去一步一步选择具体的方法来实现微前端呢?

大概可以从以下四个方面考虑,

  • 识别微前端
  • 构建微前端
  • 微前端路由
  • 微前端之间通信

识别微前端

让我们从第一个选择开始,这将对后面的决定产生重大影响。 我们需要从技术角度确定如何定义微前端,这里有2种可能的选择(如下图):

  • 水平拆分:一个页多个微前端
  • 垂直拆分:每次加载一个微前端


怎么做微前端(Micro Front end)?

在水平拆分方案中,当我们在同一页面上使用多个微前端架构时,多个团队需要协调工作,因为每个团队都负责视图(view)的一部分。

在垂直拆分方案中,每个团队都负责一个业务领域,例如 在这种情况下,通常将DDD原理应用于前端体系架构。DDD 中的另一个重要术语是有界上下文(bounded context),它是一个逻辑边界,隐藏了暴露契约以使用模型中的数据的实现细节。通常,它将由域和子域定义的业务区域转换为逻辑区域,在这些逻辑区域中,我们定义模型、代码结构和我们的团队。有界上下文通过创建它们之间的契约来定义不同上下文之间的通信方式,通常由 API表示。 这允许团队根据预先定义的契约同时处理不同的子域。通常,在新的项目中,子域会重叠有界上下文,因为我们可以自由地以尽可能好的方式设计系统,因此我们可以将特定子域分配给一个团队,以交付定义契约的特定业务价值。这里我就不对DDD展开讨论,自我学习一下。

构建微前端

构建微前端应用程序有不同的方法,可以用下图来概括(如下图):


怎么做微前端(Micro Front end)?

在这个图中,我们可以发现三种不同的方式来构建微前端体系结构:

  • 客户端构建
  • 边缘构建
  • 服务器端构建

从图的左侧开始,我们有一个客户端构建,其中应用程序 shell(这个我在前文有介绍)直接从 ContentDelieryNetwork (CDN)加载多个微型前端,如果微前端尚未缓存到 CDN级别,则直接从原始端加载。 在中间,我们在 CDN级别构建最终视图,从源(orgin)检索微前端并将最终结果交付给客户机。 右侧的最后一个图表显示了在源端构建微前端,缓存在 CDN级别,最后提供给客户端。

现在让我们看看我们如何在技术上实现此架构:

客户端构建

在这种情况下,应用程序 shell在其自身内部加载微前端,这些微前端应该具有一个 JavaScript或 HTML文件作为入口点,这样,应用程序 shell就可以在 HTML文件的情况下添加 DOM节点,或者在入口点为 JavaScript文件时初始化 JavaScript应用程序。另一种可能的方法是使用 iframe的组合来加载不同的微前端,否则我们可以在客户端通过称为client-side include.Client-side的技术在客户端使用转换机制,将空占位符标记替换为复杂组件。 例如,名为h-include的库使用占位符标记来创建对 URL的 AJAX请求,并用请求的响应替换元素的 innerHTML。这种方法提供了许多选项,但使用client-side include与使用 iframes的效果不同。

边缘构建

使用边侧构建,我们在 CDN级别构建视图。 许多 CDN提供商为我们提供了使用一种名为 Eedge Side Include (或 ESI)的基于 XML的标记语言的选择。 ESI并不是一种新的语言;在2001年, Akamai和 Oracle等提出将其作为一种标准。 ESI背后的原因是,与大多数软件通常所依赖的有限的数据中心容量相比,扩展 Web基础设施以利用 CDN网络所提供的大量存在点的可能性。这种实现的缺点之一是,每个 CDN提供商都没有以相同的方式实现 ESI;因此,多 CDN策略以及将我们的代码从一个提供商移植到另一个提供商,可能会导致大量重构和潜在的新逻辑实现。

服务器端构建

最后一种可能性是服务器端构建,它可能在运行时或编译时发生。在这种情况下,源服务器通过接受所有不同的微前端请求并组装最终的页面来构建视图。如果该页面是高度可缓存的,那么它将由 CDN以长时间生存策略提供服务;相反,如果该页面是针对每个用户个性化的,那么它将需要认真考虑最终解决方案的可伸缩性,当有许多来自不同客户端的请求时。当我们决定使用服务器端构建时,我们需要深入分析应用程序中存在的用例,如果我们决定使用运行时构建,我们需要有清晰的服务器可伸缩性策略,以避免用户停机。

在了解我们面前的可能性之后,我们需要决定哪种技术更适合我们的项目以及我们的团队结构。 混合使用各种方法也是常见的方法之一。

微前端路由

开始微前端体系结构时,一个重要的决定是如何路由应用程序视图(view)。此决定与我们打算用于实现项目的微前端体系结构非常关联。我们可以决定路由源(orgin)、边缘或客户端的页面请求(如下图)。


怎么做微前端(Micro Front end)?

当我们决定在源端(orgin)构建微前端时,如果页面未在 CDN级别缓存,我们将被迫在origin路由请求。我们可能决定在 CDN级别编排边缘计算解决方案,主要是为了减轻在orgin级别可能遇到的任何可伸缩性问题,但在边缘,负载将由 CDN提供商管理。请记住,使用边缘计算有其自身的限制和挑战,例如,代码执行时间与原点相比是有限的。 外部配置更复杂,因为我们的代码可以在多个位置上运行,因此在运行时从特定位置加载一个配置可能会增加浏览器响应的延迟,当存在点远离存储配置的位置时。通常情况下,我们可以从一个帐户同时运行的边缘计算的数量是有限制的。但是,我们需要考虑到缩放基础设施可能是非常重要的,特别是当我们必须每秒管理多个请求的突发流量时(RPS),因此我们的服务器需要跟上所有请求并快速水平缩放,然后每个应用服务器都需要检索构建要服务的页面所需的微前端。在 CDN的帮助下,我们可以减轻这个问题,主要问题是当我们拥有动态或个性化的数据时,我们不能广泛依赖 CDN为我们的页面提供服务,因为这些数据将会过时或不是个性化的。当我们决定在体系结构中使用边缘构建时,路由是基于页面 URL的,而 CDN则通过聚集边缘级别提供所需的微前端组装。另一个选项是使用客户端。 在这种情况下,我们需要根据用户状态加载微前端,例如,在用户已经通过身份验证时加载应用程序的经过身份验证的区域,或者在用户第一次访问应用程序时只加载登录页面。如果我们使用的应用程序 shell将微前端加载为SPA,则应用程序 shell负责实现路由逻辑,因此在开始时,应用程序 shell检查路由配置,然后决定加载哪个微前端。当我们有基于身份验证、地理位置定位或任何其他复杂逻辑的微前端复杂路由时,这是一种完美的方法。相反,当我们使用多页面网站时,微前端可能通过客户端转换加载。 适用于此类体系结构的路由逻辑几乎为零,因为客户端完全依赖于用户在浏览器中键入的 URL或在另一个页面中选择的超链接,这类似于我们使用边缘端 edge-side include 方法。在这两种情况下,我们不会遇到任何可伸缩性问题,当您的团队具有更强的前端技能时,强烈建议使用客户端路由,这样就可以很自然地通过后端配置进行客户端路由。这些路由方法并不相互排斥,实际情况,我们可以将 CDN与源或客户端和 CDN结合使用这些方法。重要的是我们希望如何处理应用程序的路由,因为这是我们在开始开发微前端应用程序之前需要作出的基本决定。

微前端之间通信

在理想的世界里,我们不需要在微前端之间进行通信,因为它们都是自治的。 实际上,并不总是能够将用户交互通知给其他微前端,特别是当我们在同一个页面中使用多个微前端时。当我们决定在同一个页面中使用多个微前端时,为用户管理一致且连贯的用户界面的复杂性可能非常重要。 当我们想要在不同团队拥有的微前端之间进行通信时也是如此。请记住,每个微前端应该不知道同一页面上的其他微前端,否则我们将破坏独立部署的原则。在这种情况下,我们有几个选项通知其他微前端发生了事件,我们可以在每个微前端中注入事件总线(event bus),并将事件通知给每个微前端,如果其中一些微前端对事件感兴趣,他们可以侦听并对其做出响应(如下图)。


怎么做微前端(Micro Front end)?

为了注入事件总线,我们需要所有微前端的容器来实例化事件总线并将其注入组成页面的每个微前端中。另一种解决方案可以使用自定义事件,在这种情况下,应通过对象分派自定义事件适用于所有微前端,例如窗口对象。如果您决定使用iframe实现微前端,则使用事件总线可以避免遇到诸如应从iframe内部使用哪个窗口对象这样的难题,并考虑到每个iframe拥有自己的窗口对象。无论我们是微前端的水平分割还是垂直分割,我们都需要决定如何在视图之间传递数据。想象一下,我们有一个用于登录用户的微前端,还有一个用于我们平台的身份验证部分的微前端。成功通过身份验证的微前端登录必须将令牌传递到我们平台的已认证区域。那么我们如何将令牌从一个微前端传递到另一个微前端?在这种情况下,我们有几种可能性。我们可以使用web存储(例如session或本地存储),也可以使用cookie(如下图)。


怎么做微前端(Micro Front end)?

另一个选择是通过查询字符串传递一些数据,并检索完整的细节以通过API显示(如下图)。 使用查询字符串(query string)不是传递诸如密码或用户ID之类的敏感数据的最安全方法。 实际上,如果通过HTTPS协议传递信息,则有多种方法可以获取该信息。 因此,应谨慎采用此解决方案。


怎么做微前端(Micro Front end)?

综上所述,微前端选择由4个关键因素组成:定义,构建,路由和通信。在此表中,您可以根据识别微前端的方式找到所有可用的组合。


怎么做微前端(Micro Front end)?


另外,在实际开发过程中,我们都会参考一些开源框架,结合我们上面分析以及具体业务,然后自定义一套的框架,当然有一些情况也可以直接使用。比较有名的框架,Tailor.js,HelloFresh,luigi framework等等。


分享到:


相關文章: