微前端概述
微前端概念是从微服务概念扩展而来的,摒弃大型单体方式,将前端整体分解为小而简单的块,这些块可以独立开发、测试和部署,同时仍然聚合为一个产品出现在客户面前。可以理解微前端是一种将多个可独立交付的小型前端应用聚合为一个整体的架构风格。
微前端不是一门具体的技术,而是整合了技术、策略和方法,可能会以脚手架、辅助插件和规范约束这种生态圈形式展示出来,是一种宏观上的架构。这种架构目前有多种方案,都有利弊之处,但只要适用当前业务场景的就是好方案。
常用微前端方案:
- iframe
- single-spa
- qiankun 基于 single-spa 方案实现, 更强大更易上手
- webpack5 ModuleFederationPlugin(EMP)
- microApp
- wujie-micro
single-spa太过于基础,对原有项目的改造过多,成本太高; iframe在所有微前端方案中是最稳定的、上手难度最低的,但它有一些无法解决的问题,例如性能低、通信复杂、双滚动条、弹窗无法全局覆盖,它的成长性不高,只适合简单的页面渲染。剩下的只有qiankun、microApp和wujie-micro了。
qiankun
乾坤微前端架构则进一步对single-spa方案进行完善,主要的完善点:
- 子应用资源由 js 列表修改进为一个url,大大减轻注册子应用的复杂度
- 实现应用隔离,完成js隔离方案 (window工厂) 和css隔离方案 (类vue的scoped)
- 增加资源预加载能力,预先子应用html、js、css资源缓存下来,加快子应用的打开速度
总结一下方案的优缺点:
优点
- 监听路由自动的加载、卸载当前路由对应的子应用
- 完备的沙箱方案,js沙箱做了SnapshotSandbox、LegacySandbox、ProxySandbox三套渐进增强方案,css沙箱做了两套strictStyleIsolation、experimentalStyleIsolation两套适用不同场景的方案
- 路由保持,浏览器刷新、前进、后退,都可以作用到子应用
- 应用间通信简单,全局注入
缺点
- 基于路由匹配,无法同时激活多个子应用,也不支持子应用保活
- 改造成本较大,从 webpack、代码、路由等等都要做一系列的适配
- css 沙箱无法绝对的隔离,js 沙箱在某些场景下执行性能下降严重
- 无法支持 vite 等 ESM 脚本运行
成本上:
- 接入成本:子应用需要接入生命周期代码;主应用需要接入注册微应用代码;
- 改造成本:需要自己考虑微前端工程化问题,以及微前端平台运维。
风险上:
- 社区活跃度:github star 数量 13.4k (统计时间2022-10-09)
- 文档齐全,demo多
micro-app
京东1年前出品,官网地址:https://micro-zoe.github.io/micro-app/
功能上:
- 抛弃了路由劫持的思路,选用类web component的方案
- 基于CustomElement和样式隔离、js隔离来实现微应用的加载,所以子应用无需改动就可以接入
- 支持应用隔离
- 通过劫持底层接口实现了元素隔离
- 提供了插件系统
- 支持预加载
- 没有考虑工程化问题:如公用依赖,组件复用
- 没有考虑到微前端平台运维
- 不支持vite
成本:
- 接入成本:子应用无需改动,主应用需要接入微应用代码
- 改造成本:需要自己考虑微前端工程化问题,以及微前端平台运维。
风险:
- 这个框架基于CustomElement和Proxy API,前者针对低版本有polyfill,但后者没有,且目前官方文档说没有做兼容的计划
- 社区活跃度 star 3.5k(统计时间2022-10-09)
- 文档齐全
wujie
腾讯今年7月份出品,官网地址:https://wujie-micro.github.io/doc/guide/start.html。
功能上:
- 支持vite
- 多应用同时激活在线
- 框架具备同时激活多应用,并保持这些应用路由同步的能力
- 组件式的使用方式
- 无需注册,更无需路由适配,在组件内使用,跟随组件装载、卸载
- 应用级别的 keep-alive
- 子应用开启保活模式后,应用发生切换时整个子应用的状态可以保存下来不丢失,结合预执行模式可以获得类似ssr的打开体验
- 纯净无污染
- 无界利用iframe和webcomponent来搭建天然的js隔离沙箱和css隔离沙箱
- 利用iframe的history和主应用的history在同一个top-level browsing context来搭建天然的路由同步机制
- 副作用局限在沙箱内部,子应用切换无需任何清理工作,没有额外的切换成本
- 性能和体积兼具
- 子应用执行性能和原生一致,子应用实例instance运行在iframe的window上下文中,避免with(proxyWindow){code}这样指定代码执行上下文导致的性能下降,但是多了实例化iframe的一次性的开销,可以通过 proload 提前实例化
- 体积比较轻量,借助iframe和webcomponent来实现沙箱,有效的减小了代码量
成本:
- 开箱即用
- 不管是样式的兼容、路由的处理、弹窗的处理、热更新的加载,子应用完成接入即可开箱即用无需额外处理,应用接入成本也极低
风险:
- 太新了,今年7月份才发布
- 社区活跃度 star 1.7k(统计时间2022-10-09)
- 文档齐全
微前端总结
qiankun 方案对 single-spa 微前端方案做了较大的提升同时也遗留下来了不少问题长时间没有解决; micro-app 方案对 qiankun 方案做了较多提升但基于 qiankun 的沙箱也相应会继承其存在的问题; EMP 方案基于 webpack 5 联邦编译则约束了其使用范围; 目前的微前端方案在用户的核心诉求上都没有很好的满足,有很大的优化提升空间。
正常的一些轻量业务,是没有必要引入微前端的概念,这样只会自找麻烦,只有在业务触及了巨石应用范畴,给开发人员带来困扰的时候,才需要引入,以便解决一下通用问题,并保证具备以下能力:
- 自主的团队,维护着各团队解耦的代码库;
- 独立部署:各团队可以独立部署;
- 同步更新:各团队各业务功能升级后,整体应用能够同步更新;
- 增量升级:做到不修改历史包袱的情况下,进行逐步的更新;
适合的业务场景:
- 前端巨石工程:业务越来越复杂,许多复杂需求堆积在一个工程里,部署、debug、扩展过于困难,单个模块的重构成本大。
- 前端碎石工程:不同项目之间的依赖维护成本巨大、项目之间的跳转体验糟糕。
具体什么样的情形适合使用微前端?
- 技术栈切换又不想重构已有业务的,例如增量升级,就是在保留原来项目部分的基础上,新功能或者模块采用新技术来实现。
- 历史包袱项目,比如历史项目内部强耦合,但是又运行稳定的。
- 自己造的轮子的库(与业务相关)需要复用在新项目中。
- 旧项目的业务页面会在新项目中复用,又迫于项目时间压力的情况。
场景1:老项目使用的jquery,新项目使用的是vue,两个项目都要共存。或者老项目是使用的jquery,突然要在老项目上开发新功能,jquery没有什么人用了,此时使用其他技术,例如vue开发新功能。
场景2:一个项目里面的不同功能模块由不同的前端技术团队在做,两个前端团队采用的是不同的技术栈,且各个团队相对独立,独立仓库、独立部署、独立构建。
当前调度项目采用微前端会面临哪些问题?
- 第三方依赖重复引用的问题,导致需要加载太多的资源
- 组件如何复用的问题。每个应用都有自己开发的组件库
- 构建流水线增加,原先一条,现在要几条,服务器端口增加,之前是一个现在是几个。
- 代码仓库增加,原先一个,现在N个。
- 子应用首先需要做支持跨域请求改造,这个是所有微前端框架运行的前提。