• 欢迎访问新概念博客,研究javascript,css3,html5,nodejs,Ext js等技术研究,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站,欢迎加入新概念博客

什么是微前端,为什么会有微前端,实现微前端有哪些方案?微前端入门

欣赏 新概念 来源:掘金 9个月前 (11-02) 536次浏览 0个评论 扫描二维码

引言

把前端做好很难,让多个团队同时开发大型前端应用,就更难了。目前有一种趋势是将前端应用拆分成更小、更易于管理的小应用。这种体系结构是如何提高前端团队的效率的呢?

本文将对这些问题进行阐述。除了讨论利弊,我们还将介绍一些可用的例子,并深入研究一个完整的示例应用。


近年来,微服务已迅速普及,许多组织都使用这种体系结构样式来避免大型单体应用的局限性。尽管有很多介绍微服务的文章,但还是有许多公司局限于单体式前端应用。

假设你想构建一个渐进式的 Web 应用程序,但是你很难将新的功能实现于现有的整体应用中。比如你想开始使用新的 JS 语法(或 TypeScript),但是你无法在现有的构建过程中使用对应的构建工具。又或者,你只想扩展你的开发团队,以便多个团队可以同时处理一个产品,但是现有应用中的耦合和复杂度让每个开发者互相掣肘。这些都是真实存在的问题,这些问题极大地降低了大型团队的开发效率。

最近,我们看到越来越多前端开始把注意力集中在复杂前端应用的架构上面。尤其是如何将前端整体分解,每一块可以独立开发、测试和部署,同时对用户而言仍是一个整体。这种技术就是微前端,我们将其定义为:一种将独立的前端应用组成一个更大的整体的架构风格

当然,在软件体系结构方面没有免费的午餐。一些微型前端实现可能导致依赖关系非常重复,从而增加用户的下载量。而且,团队自治可能会导致团队分散。尽管如此,我们认为风险是可控的,收益是高于成本的。

什么是微前端,为什么会有微前端,实现微前端有哪些方案?微前端入门

什么是微前端?

微前端(Micro-Frontends)是一种类似于微服务的架构,它将微服务的理念应用于浏览器端,即将 Web 应用由单一的单体应用转变为多个小型前端应用聚合为一的应用。各个前端应用还可以独立运行、独立开发、独立部署。微前端不是单纯的前端框架或者工具,而是一套架构体系,这个概念最早在 2016 年底被提出,可以参考在 Google 上搜索 Micro-Frontends, 排名靠前的 https://micro-frontends.org 的博客文章,提出了早期的微前端模型。

为什么会有微前端

任何新技术的产生都是为了解决现有场景和需求下的技术痛点,微前端也不例外:

  1. 拆分和细化:当下前端领域,单页面应用(SPA)是非常流行的项目形态之一,而随着时间的推移以及应用功能的丰富,单页应用变得不再单一而是越来越庞大也越来越难以维护,往往是改一处而动全身,由此带来的发版成本也越来越高。微前端的意义就是将这些庞大应用进行拆分,并随之解耦,每个部分可以单独进行维护和部署,提升效率。
  2. 整合历史系统:在不少的业务中,或多或少会存在一些历史项目,这些项目大多以采用老框架类似(Backbone.js,Angular.js 1)的 B 端管理系统为主,介于日常运营,这些系统需要结合到新框架中来使用还不能抛弃,对此我们也没有理由浪费时间和精力重写旧的逻辑。而微前端可以将这些系统进行整合,在基本不修改来逻辑的同时来同时兼容新老两套系统并行运行。

实现微前端有哪些方案

单纯根据对概念的理解,很容易想到实现微前端的重要思想就是将应用进行拆解和整合,通常是一个父应用加上一些子应用,那么使用类似Nginx配置不同应用的转发,或是采用 iframe 来将多个应用整合到一起等等这些其实都属于微前端的实现方案,他们之间的对比如下图:

方案 描述 优点 缺点
Nginx路由转发 通过Nginx配置反向代理来实现不同路径映射到不同应用,例如 www.abc.com/app1 对应 app1,www.abc.com/app2 对应 app2,这种方案本身并不属于前端层面的改造,更多的是运维的配置。 简单,快速,易配置 在切换应用时会触发浏览器刷新,影响体验
iframe 嵌套 父应用单独是一个页面,每个子应用嵌套一个 iframe,父子通信可采用 postMessage 或者 contentWindow 方式 实现简单,子应用之间自带沙箱,天然隔离,互不影响 iframe 的样式显示、兼容性等都具有局限性;太过简单而显得 low
Web Components 每个子应用需要采用纯 Web Components 技术编写组件,是一套全新的开发模式 每个子应用拥有独立的 script 和 css,也可单独部署 对于历史系统改造成本高,子应用通信较为复杂易踩坑
组合式应用路由分发 每个子应用独立构建和部署,运行时由父应用来进行路由管理,应用加载,启动,卸载,以及通信机制 纯前端改造,体验良好,可无感知切换,子应用相互隔离 需要设计和开发,由于父子应用处于同一页面运行,需要解决子应用的样式冲突,变量对象污染,通信机制等技术点

 

微前端的优点

增量升级

对于许多团队而言,这是开始微前端之旅的首要原因。技术债阻碍了项目的发展,只能重写。为了避免完全重写的风险,我们更希望 逐个替换旧的模块

简单、解耦的代码库

每个单独的微型前端应用的源代码都将比单个整体前端应用的源代码少得多。这些较小的代码库对于开发人员来说更容易维护。尤其是我们避免了组件间耦合所导致的复杂性。

独立部署

就像微服务一样,微前端的独立部署能力是关键。部署范围的减小,带来了风险的降低。每个微前端应用都应具有自己的持续交付途径,不停地构建、测试、部署。

团队自治

每个团队需要围绕业务功能垂直组建,而不是根据技术能力来组建。这为团队带来了更高的凝聚力。

微前端由哪些模块组成

基于上文,当下微前端主要采用的是组合式应用路由方案,该方案的核心是“主从”思想,即包括一个基座(MainApp)应用和若干个微(MicroApp)应用,基座应用大多数是一个前端 SPA 项目,主要负责应用注册,路由映射,消息下发等,而微应用是独立前端项目,这些项目不限于采用 React,Vue,Angular 或者 JQuery 开发,每个微应用注册到基座应用中,由基座进行管理,但是如果脱离基座也是可以单独访问,基本的流程如下图所示:

当整个微前端框架运行之后,给用户的体验就是类似下图所示:

简单描述下就是基座应用中有一些菜单项,点击每个菜单项可以展示对应的微应用,这些应用的切换是纯前端无感知的,所以,基于目前的方案来说,一个微前端的基座框架需要解决以下问题:

  1. 路由切换的分发问题。
  2. 主微应用的隔离问题。
  3. 通信问题。

下面针对这些问题来一一阐述。

微前端的路由分发

作为微前端的基座应用,是整个应用的入口,负责承载当前微应用的展示和对其他路由微应用的转发,对于当前微应用的展示,一般是由以下几步构成:

  1. 作为一个 SPA 的基座应用,本身是一套纯前端项目,要想展示微应用的页面除了采用 iframe 之外,要能先拉取到微应用的页面内容, 这就需要远程拉取机制
  2. 远程拉取机制通常会采用 fetch API 来首先获取到微应用的 HTML 内容,然后通过解析将微应用的 JavaScript 和 CSS 进行抽离,采用 eval 方法来运行 JavaScript,并将 CSS 和 HTML 内容 append 到基座应用中留给微应用的展示区域,当微应用切换走时,同步卸载这些内容,这就构成的当前应用的展示流程。
  3. 当然这个流程里会涉及到 CSS 样式的污染以及 JavaScript 对全局对象的污染,这个涉及到隔离问题会在后面讨论,而目前针对远程拉取机制这套流程,已有现成的库来实现,可以参考import-html-entrysystem.js

对于路由分发而言,以采用 vue-router 开发的基座 SPA 应用来举例,主要是下面这个流程:

  1. 当浏览器的路径变化后,vue-router 会监听 hashchange 或者 popstate 事件,从而获取到路由切换的时机。
  2. 最先接收到这个变化的是基座的 router,通过查询注册信息可以获取到转发到那个微应用,经过一些逻辑处理后,采用修改 hash 方法或者 pushState 方法来路由信息推送给微应用的路由,微应用可以是手动监听 hashchange 或者 popstate 事件接收,或者采用 React-router,vue-router 接管路由,后面的逻辑就由微应用自己控制。

微前端的应用隔离

应用隔离问题主要分为主应用和微应用,微应用和微应用之间的 JavaScript 执行环境隔离,CSS 样式隔离,我们先来说下 CSS 的隔离。

CSS 隔离:当主应用和微应用同屏渲染时,就可能会有一些样式会相互污染,如果要彻底隔离 CSS 污染,可以采用 CSS Module 或者命名空间的方式,给每个微应用模块以特定前缀,即可保证不会互相干扰,可以采用 webpack 的 postcss 插件,在打包时添加特定的前缀。

而对于微应用与微应用之间的 CSS 隔离就非常简单,在每次应用加载时,将该应用所有的 link 和 style 内容进行标记。在应用卸载后,同步卸载页面上对应的 link 和 style 即可。

JavaScript 隔离:每当微应用的 JavaScript 被加载并运行时,它的核心实际上是对全局对象 Window 的修改以及一些全局事件的改变,例如 jQuery 这个 js 运行后,会在 Window 上挂载一个window.$对象,对于其他库 React,Vue 也不例外。为此,需要在加载和卸载每个微应用的同时,尽可能消除这种冲突和影响,最普遍的做法是采用沙箱机制(SandBox)。

沙箱机制的核心是让局部的 JavaScript 运行时,对外部对象的访问和修改处在可控的范围内,即无论内部怎么运行,都不会影响外部的对象。通常在 Node.js 端可以采用 vm模块,而对于浏览器,则需要结合 with 关键字和 window.Proxy 对象来实现浏览器端的沙箱。

微前端的消息通信

应用间通信有很多种方式,当然,要让多个分离的微应用之间要做到通信,本质上仍离不开中间媒介或者说全局对象。所以对于消息订阅(pub/sub)模式的通信机制是非常适用的,在基座应用中会定义事件中心 Event,每个微应用分别来注册事件,当被触发事件时再有事件中心统一分发,这就构成了基本的通信机制,流程如下图:

当然,如果基座和微应用采用的是 React 或者是 Vue,是可以结合 Redux 和 Vuex 来一起使用,实现应用之间的通信。

微前端有哪些框架

基于上述对微前端整体概念和理论的阐述,目前业界已经有不少框架来帮助开发者轻松的集成微前端架构,例如下面这些:

  • Mooa:基于 Angular 的微前端服务框架
  • Single-Spa:最早的微前端框架,兼容多种前端技术栈。
  • Qiankun:基于 Single-Spa,阿里系开源微前端框架。
  • Icestark:阿里飞冰微前端框架,兼容多种前端技术栈。
  • Ara Framework:由服务端渲染延伸出的微前端框架。

上面这些框架,各位读者感兴趣的话可以来亲自试试。

是否要用微前端

微前端帮助开发者解决了实际的问题,但是对于每个业务来说,是否适合使用微前端,以及是否正确的使用微前端,还是需要遵循以下一些原则:

  1. 微前端最佳的使用场景是一些 B 端的管理系统,既能兼容集成历史系统,也可以将新的系统集成进来,并且不影响原先的交互体验。
  2. 整体的微前端不仅仅是只将系统集成进来,而是整个微前端体系的完善,这其中就包括:1):基座应用和微应用的自动部署能力。2):微应用的配置管理能力。3):本地开发调试能力。4):线上监控和统计能力等等。只有将整个能力体系搭建完善,才能说是整个微前端体系流程的完善。
  3. 当发现使用微前端反而使效率变低,简单的变更复杂那就说明微前端并不适用。

总结

简而言之,微前端就是将大而恐怖的东西切成更小、更易于管理的部分,然后明确地表明它们之间的依赖性。我们的技术选择,我们的代码库,我们的团队以及我们的发布流程都应该能够彼此独立地操作和发展,无需过多的协调。

上述方案中,每种都有自己的优劣,最原始的Nginx配置反向代理是从接入层的角度来将系统进行分离,但是需要运维配置,而 iframe 嵌套是最简单和最快速的方案,但是 iframe 的弊端也是无法避免的,而 Web Components 的方案则需要大量的改造成本,最后的组合式应用路由分发方案改造成本中等并且能满足大部分需求,也不影响各前端应用的体验,是当下各个业务普遍采用的一种方案,本文后面的内容也是主要基于这种方案进行阐述。


新概念博客 , 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:什么是微前端,为什么会有微前端,实现微前端有哪些方案?微前端入门
喜欢 (0)
[新概念]
分享 (0)
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址