当前市面上已出现了很多微前端方案,如何做出正确的选择是一件不容易的事情。
在开始介绍这些方案之前,我们有必要先了解一下微前端架构的核心原则,从而更好的去衡量微前端方案是否成熟。
核心原则
应用独立
这里说的独立包含三个方面:
- 独立开发:每个微应用由不同业务团队开发,实现团队自治。
- 独立部署:微应用可独立部署运行,每个应用可以有自己的交付部署流程,某个微应用出现故障不影响其他应用。
- 独立运行:既可以组合运行,也可以单独运行,运行时环境隔离,提供JavaScript沙箱,CSS 样式隔离,避免应用间运行时污染。
消息通信
完善的通信机制,可以降低主应用和微应用、微应用和微应用之间的数据共享难度,是否有完善的通信机制是选型考量的一个关键因素。
技术栈无关
主应用不限制子应用接入的技术栈。不限制技术栈有如下好处:
- 每个应用可以结合团队情况选择不同的技术栈,也可以集成一些采用了不同技术栈的老旧项目。
- 应用技术栈切换升级不影响其他应用,可以实现增量升级。通常我们很难对一个已有的系统做全量的技术栈升级或重构,而微前端是一种非常好的实施渐进式重构的手段和策略。
依赖复用
解决各应用间依赖、公共逻辑需要重复维护的问题。应用间相同的依赖需要重复下载。
方案对比
接下来,我们从四大流派来看一下当下有哪些方案可以选择,并简单做个对比:
传统式
1. 路由分发(服务端)
描述: 在HTTP服务器通过反向代理将不同的路由分发到对应的应用上。
http {
server {
listen 80;
server_name www.phodal.com;
location /api/ {
proxy_pass http://http://172.31.25.15:8000/api;
}
location /web/admin {
proxy_pass http://172.31.25.29/web/admin;
}
location /web/notifications {
proxy_pass http://172.31.25.27/web/notifications;
}
location / {
proxy_pass /;
}
}
}
优点: 简单、快速、易配置。
缺点:
- 应用是完全分开的,通信和数据资源共享很困难;
- 切换应用需要刷新页面,体验不好;
- 完全是基于路由的,无法同时加载多个应用。
2. IFrame
描述: 将微应用通过iframe载入。
**优点:**接入简单,兼容性好,原生支持沙箱隔离。
缺点:
- 隔离性无法突破,应用间上下文无法共享,比如在子应用弹窗问题(只能基于子应用可视区定位,不能基于整个页面定位)。
- 应用间通信需要自行实现一套基于postMessage的通信机制。
- 刷新会导致iframe Url状态丢失,iframe 和主页面共用一个浏览历史,后退前进按钮无法使用。
自组织式
3. Npm集成
描述: 将微应用抽离成包的方式,发布到Npm中,再在主应用中将这些微应用作为依赖项,构建时候集成进项目中。
优点: 开发与接入成本低,容易理解。
缺点:
- 影响主应用编译速度和打包后的体积。
- 不支持动态更新,npm包更新后,需要重新更新包,主应用需要重新发布部署。
- 因为业务应用不能发布到公开库,需要自己搭建npm私有库,提高了工程难度。
4. JS集成
**描述:**每个微应用提供一个入口js,会导出一个全局变量,主应用引入该js,安装应用时调用相关函数,挂载渲染微应用。
**优点:**相比Npm集成方案,优化的地方是微应用不用构建到主应用中,而是独立构建的。
缺点: 规范、通信、沙箱都需要自己实现,依赖开发人员设计能力。
<html>
<head>
<title>Feed me!</title>
</head>
<body>
<h1>Welcome to Feed me!</h1>
<!-- 这些脚本不会马上渲染应用 -->
<!-- 而是分别暴露全局变量 -->
<script src="https://browse.example.com/bundle.js"></script>
<script src="https://order.example.com/bundle.js"></script>
<script src="https://profile.example.com/bundle.js"></script>
<div id="micro-frontend-root"></div>
<script type="text/javascript">
// 这些全局函数是上面脚本暴露的
const microFrontendsByRoute = {
'/': window.renderBrowseRestaurants,
'/order-food': window.renderOrderFood,
'/user-profile': window.renderUserProfile,
};
const renderFunction = microFrontendsByRoute[window.location.pathname];
// 渲染第一个微应用
renderFunction('micro-frontend-root');
</script>
</body>
</html>
微件式
5. Web Component
**描述:**微应用导出的是一个自定义元素(Web Component),加载微应用时渲染对应的元素即可。
**优点:**浏览器自带能力,接入简单,自带Shadow DOM沙箱。
**缺点:**兼容性不太好,暂时只有较新的浏览器支持,但未来可期。
6. MicroApp
描述: [MicroApp](https://cangdu.org/micro-app/是京东零售推出的一款微前端框架,是基于WebComponent实现的一种用于构建微前端应用的极简方案。
**优点:**接入成本很低,只需一行代码即可实现微前端,提供了js沙箱
、样式隔离
、元素隔离
、预加载
、数据通信
、静态资源补全
等一系列完善的功能。
**缺点:**依赖于CustomElements和Proxy两个较新的API,兼容性需要考虑。
7. EMP
描述: EMP由欢聚时代(YY)自主研发的单页微前端解决方案,主要基于Webpack5的新特性Module Federation实现。
**优点:**强调去中心化,每个微应用都可以引入其他的微应用,无中心应用(容器/主应用)的概念。
缺点:
- 接入有一定成本,不同技术栈接入有一定难度;
- 因为使用了Module Federation,所以仅支持webpack5+构建的应用。
基座式
7. Single-spa
描述:Single-spa在上面的js集成方案,加入了生命周期,算是比较老牌的微前端框架了。
**优点:**支持生命周期和代码延迟加载。
**缺点:沙箱环境需要自行处理,有一定的侵入性。
8. qiankun
描述:qiankun由蚂蚁团队基于single-spa构建的微前端解决方案,功能比较完善,已有多个成功应用案例验证,是目前应用最多的微前端框架。
优点:
- 接入成本相对较低,框架本身已包含构建微前端系统时所需要的基本能力。
- 微应用入口支持多种方式。
**缺点:**没有提供依赖复用,需要自行解决。
9. icestark
描述: icestark是阿里飞冰出品的面向大型系统的微前端解决方案。
**优点:**相比qiankun,支持微模块,一种粒度更小的挂件,可以随处挂载。
**缺点:**样式隔离问题目前还只能靠规范来规避,Shadow DOM方案还在实验中。
10. Garfish
描述:Garfish是字节跳动出品,包含构建微前端系统时所需要的基本能力。
**优点:**api简单,接入成本低,自带依赖共享api,支持插件扩展。
路在何方
可以看到,在上述方案中,比较成熟的方案有MicroApp、EMP、qiankun、Garfish。当下微前端相应的解决方案其实挺多的,但是并不存在银弹,每一个方案都有优缺点,只有结合实际需求进行选择最合适的那个方案就行。
当然除了前面说的几个微前端的核心原则,一般在选型时,我们还注意如下几个纬度:
纬度 | 描述 |
---|---|
稳定性 | 该方案是否经历了社区的考验,有较多的成熟案例,同时保持较高的活跃性,有完善的文档。 |
可拓展性 | 支持定制化开发,提供较高的可拓展能力,同时成本可以在接受范围内 |
可控性 | 发生问题后,能够在第一时间内进行问题排查,以最快的响应速度来处理问题,修复的方案是否会依赖于外部环境 |
低成本 | 学习成本和项目接入改造成本是一个很重要的考量因素,成本太高会适得其反。 |
所以,结合上述和项目的一些因素,当时我们最终选择了qiankun。接下来我们就聊一聊qiankun。