微前端架构简介-2

Posted by huangqing on May 19, 2020

起源

微前端的概念是随着后端微服务的兴起,导致业务团队被分割为不同的小的开发团队,每个团队中有前后端,测试等角色,后端服务间可以通过http或者rpc互相调用,也可以通过api gateway进行接口的集成聚合,随之而来的是希望前端团队也能够独立开发微应用,然后在前端某个阶段(build,runtime)将这些微应用聚合起来,形成一个完整的大型web应用。于是这个概念在2016年thoughtworks技术雷达中被提出来了。

页面应用出现后,每个团队不能按照以前那种服务端路由直出套模板的模式去开发页面了,整个路由都是被前端接管,所以最重要的两个问题就是web应用如何集成以及在哪个阶段集成,对应不同选择最终的实现方案也会有很大差异,这取决于你的业务场景,但是对于大多数团队,考虑微前端这种架构模式通常的诉求都是下面这样的:

  • 独立开发,独立部署,增量更新:对应上图,团队A,B,C最好互相无感知,每个子应用完全按照自己的版本节奏去开发,部署,更新。
  • 技术栈无关:团队A,B,C可以按照自己的需要选用任意框架开发,不需要强制保持一致
  • 运行时隔离与共享:在运行时,应用A,B,C组成了一个完整应用,通过主应用入口访问,需要保证A, B,C对应的js以及css互相隔离不受影响,同时有通信机制保证A,B, C能够互相通信或数据共享。
  • 单页面应用的良好体验:从一个子应用切换到另一个子应用的时候,路由变化不会reload整个页面,切换效果如同单页面应用的站内路由切换。

web集成方式

构建时集成

通过git submodule或者npm package在构建阶段集成在主应用仓库中,团队A,B,C独立开发,优点是实施简单,依赖也可以共享,缺点是A,B,C无法独立更新,其中一个发生更新,都需要主应用进行构建部署来更新完整应用。如下:

这种方式更适合于小团队,因为当package越来越多的时候,会导致主应用频繁发布更新,此外还会让主应用的构建速度增长,代码维护成本越来越高,所以大多数选择微前端架构的,都是希望能够在运行时集成

服务端模板集成

在主应用的首页中定义模板,通过类似于nginxSSI这样的技术让服务端通过路由动态选择集成团队A,B,C哪个子应用

团队A, B,C最终产出的是位于服务器上的某个模板文件,类似于PHP,JSP服务端集成基本上都是这样的原理,在服务端通过路由选择不同模板,拼装好首页内容并返回。这种模式首先是违背前后端分离的大趋势,会造成耦合,同时为了又需要花一定量的工作去维护server端,不适用于大型单页面应用集成的场景。

运行时Iframe集成

可以说这种方式早期应该是最简单有效的,不同团队独立开发部署,只需要一个主应用通过iframe指向应用A, B,C对应的地址即可,如果需要主应用以及子应用之间通信,通过post message也能够很容易做到。

运行时JS集成

js bundle

将应用A, B,C打包成为不同的bundle,然后通过loader加载不同bundle,动态运行bundle的逻辑,渲染页面,如下:

这个时候应用A, B,C完全是互相无感知的,可以采用任何框架开发,路由切换导致的应用切换也不会造成页面reload,在运行时如果A,B,C想进行通信使用CustomEvent或者自定义EventBus都可以,A,B,C也可以通过不同框架本身的隔离机制或者通过一些沙箱机制实现应用隔离。

web components

使用web components,应用A, B,C将自己的业务逻辑最终写成一个 web components并到打包成一个bundle,然后由主应用来加载,执行并渲染.

这种方式一般会有浏览器兼容性问题(需要引入polyfill),对三大框架的使用者来讲,并不是很友好。如果页面某些区域(一小块)需要独立开发部署的话,可以采用这种集成方式。目前有很多框架已经考虑到了上述的一些限制,最大限度的进行了优化,达到开箱即用的效果,这里推荐 stencil ,可以帮助你快速开发。

DevUI前端集成模式演进

  1. 有很多个服务,每个服务有自己的前端代码仓库,需要独立开发,测试,部署;
  2. 每个服务的前端都是由headercontent内容区域组成的,都是一个基于Angular的单页面应用,服务间只有content内容区域不同,header都是一样的;

简单来讲,就是各业务团队独立的开发,通过路由分发到对应不同的服务,每个服务的前端都是一个完整的单页面应用。

阶段一:公共组件化 + 服务间超链接

我们将每一个服务都使用的header等区域独立出来做成了组件,以此来解决复用问题,服务间跳转仍然是使用最普通的超链接

这个阶段最大的遗留问题是:服务间跳转白屏明显,服务间session管理割裂,服务间跳转需要重新验证,用户体验极差。

阶段二:App Shell(Pre render) + Session共享

关于单页面应用渲染白屏的问题业内是有标准解决办法的,通常使用的是SSR(服务端渲染)以及预渲染(Prerender)

  • SSR会在服务端(通常是Node)执行一些逻辑,将当前路由对应的HTML 首先生成,然后再返回给浏览器
  • Prerender通常是在build阶段根据一些规则已经生成了对应的HTML内容,用户访问的时候直接返回给浏览器

Prerender:

通过这种渐进式渲染 + 预渲染模型+子域名session共享,提升了用户体验,虽然是多页面应用,但是服务间跳转经过优化给人的感觉还是站内跳转,同时又能够保证不同团队独立开发,部署。

公共组件仍然作为npm包的形式下发给到不同服务,一旦header上的公共逻辑更新,会导致每个业务都要被动发布版本

阶段三:widget(微应用)

通过类似于web components这种方式来实现(实际过程中你可以选用任何框架,只要它能满足加载bundle,执行逻辑并渲染这样的模式即可)

解决了公共逻辑更新导致业务被动更新的问题,大大减少了业务的工作并大大提升了公共逻辑更新回退的响应速度,业务与公共逻辑独立开发部署。

阶段四:跨应用的编排与集成 (微前端)

设想这样一个场景,对于一个大型企业来讲,内部有很多个中后台应用,可以把它想象为一个应用池(应用市场),对于某些业务,我希望从应用市场中拿出来 C,D ,E把它们都整合起来,形成一个大型业务A,供用户使用,同时我又希望从应用市场拿出来D, E, F,把他们整合成一个大型业务B,提供统一入口供用户使用,其中,A, B,C,D,E,F这些应用都是由不同团队开发维护的。在这种情况下,就需要有一种机制去定义一个标准的子应用需要去遵循什么样的规则,主应用如何去集成(加载,渲染,执行逻辑,隔离,通信,响应路由,依赖共享,框架无关等等)

-

微前端在企业级应用中的实践(上)