是什么
- 微前端是指存在于浏览器中的微服务。
- 微前端是一种类似于微服务的架构,它将微服务的理念应用于浏览器端,即将Web应用由单一的单体应用转变为多个小型前端应用聚合为一的应用。各个前端应用还可以独立运行、独立开发、独立部署。
- 微前端不是单纯的前端框架或者工具,而是一套架构体系。
意义
微前端所解决的现有场景和需求下的技术痛点:
- 拆分和细化:单页应用越来越庞大,越来越难以维护,往往是改一处而动全身,由此带来的开发成本高。微前端可以将这些庞大应用进行拆分,并随之解耦,每个部分都可以单独进行维护和部署,提升效率。
- 整合历史系统:业务中可能存在一些历史项目,无法抛弃,需要结合到新框架中来使用,但重写旧的逻辑太过耗时耗力。微前端可以将这些系统进行整合,在基本不修改逻辑的同时,兼容新老两套系统并运行。
实现方案
微前端的重要思想就是将应用进行拆解和整合,通常是一个父应用加上一些子应用。
方案如下:
方案 | 描述 | 优点 | 缺点 |
Nginx 路由转发 | 通过 Nginx 配置反向代理来实现不同路径映射到不同应用,例如 www.abc.com/app1 对应 app1,www.abc.com/app2 对应 app2,这种方案本身并不属于前端层面的改造,更多的是运维的配置。 | 简单,快速,易配置 | 在切换应用时会触发浏览器刷新,影响体验 |
iframe 嵌套 | 父应用单独是一个页面,每个子应用嵌套一个 iframe,父子通信可采用 postMessage 或者 contentWindow 方式。 | 实现简单,子应用之间自带沙箱,天然隔离,互不影响 | iframe 的样式显示、兼容性等都具有局限性;太过简单而显得 low |
Web Components | 每个子应用需要采用纯 Web Components 技术编写组件,是一套全新的开发模式 | 每个子应用拥有独立的 script 和 css,也可单独部署 | 对于历史系统改造成本高,子应用通信较为复杂易踩坑 |
组合式应用路由分发 | 每个子应用独立构建和部署,运行时由父应用来进行路由管理,应用加载,启动,卸载,以及通信机制 | 纯前端改造,体验良好,可无感知切换,子应用相互隔离 | 需要设计和开发,由于父子应用处于同一页面运行,需要解决子应用的样式冲突,变量对象污染,通信机制等技术点 |
- 最原始的方案:Nginx 配置反向代理是从接入层的角度将系统进行分离,但是需要运维配置
- 最简单和最快速的方案:iframe 嵌套
- Web Components 的方案:需要大量的改造成本
- 当下普遍采用的方案:组合式应用路由分发,改造成本中等,且能满足大部分需求,也不影响各前端应用的体验
组成 Of 组合式应用路由
- 组合式应用路由方案的核心是“主从”思想,即包括一个基座应用(MainApp)和若干个微应用(MicroApp)。
- 基座应用大多数是一个前端 SPA 项目,主要负责应用注册、路由映射、消息下发等
- 微应用是独立前端项目,这些项目不限于采用 React、Vue、Angular 或者 JQuery开发,每个微应用注册到基座应用中,由基座进行管理,如果脱离基座也是可以单独访问。
- 微前端框架运行之后,给用户的体验就是类似下图所示:
- 即,基座应用有一些菜单项,点击每个菜单项可以展示对应的微应用,这些应用的切换是纯前端无感知的。
- 基于目前的方案来说,一个微前端的基座框架需要解决以下问题:
- 路由切换的分发问题
- 主微应用的隔离问题
- 通信问题
微前端的路由分发
- 作为微前端的基座应用,是整个应用的入口,负责承载当前微应用的展示和对其他路由微应用的转发。
- 对于当前微应用的展示,一般是由以下几步构成:
- 作为一个 SPA 的基座应用,本身是一套纯前端项目,要想展示微应用的页面除了采用 iframe 之外,要能先拉取到微应用的页面内容,这就是远程拉取机制
- 远程拉取机制通常会采用 fetch API 来首先获取到微应用的 HTML 内容,然后通过解析将微应用的 JavaScript 和 CSS 进行抽离,采用 eval 方法 来运行 JavaScript,并将 CSS 和 HTML 内容 append 到基座应用中留给微应用的展示区域,当微应用切换走时,同步卸载这些内容,这就构成当前应用的展示流程。
- 对于路由分发而言,以采用 vue-router 开发的基座 SPA 应用来举例,主要是下面这个流程:
- 当浏览器的路径变化后,vue-router会监听 hashchange 或者 popstate 事件,从而获取到路由切换的时机
- 最先接收到这个变化的是基座的 router,通过查询注册信息可以获取到转发到哪个微应用,经过一些逻辑处理后,采用修改 hash 方法或者 pushState 方法来把路由信息推送给微应用的路由,微应用可以是手动监听 hashchange 或者 popstate 事件接收,或者采用 React-router,vue-router 接管路由,后面的逻辑就由微应用自己控制。
微前端的应用隔离
- 应用隔离问题主要分为主应用和微应用,微应用和微应用之间的 JavaScript 执行环境隔离,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 对象来实现浏览器端的沙箱。
- CSS 隔离:
微前端的消息通信
- 消息订阅(pub/sub)模式的通信机制非常适用,在基座应用中会定义事件中心 Event,每个微应用分别来注册事件,当被触发事件时再有事件中心统一分发,这就构成了基本的通信机制,流程如下图:
- 如果基座和微应用采用的是 React 或者是 Vue,是可以结合 Redux 和 Vuex 来一起使用,实现应用之间的通信。
微前端的框架
- Mooa:基于 Angular 的微前端服务框架
- Single-Spa:最早的微前端框架,兼容多种前端技术栈
- QianKun:基于 Single-Spa,阿里系开源微前端框架
- Icestark:阿里飞冰微前端框架,兼容多种前端技术栈
- Ara Framework:由服务端渲染延伸出的微前端框架
微前端的原则
- 微前端最佳的使用场景是一些B端的管理系统,既能兼容集成历史系统,也可以把新的系统集成进来,并且不影响原先的交互体验。
- 整体的微前端不仅仅是只将系统集成进来,而是整个微前端体系的完善,这其中就包括:
- 基座应用和微应用的自动部署能力
- 微应用的配置管理能力
- 本地开发调试能力
- 线上监控和统计能力等等