微前端是最近一年以来前端领域非常火的一个概念,同时集团内也衍生了很多相关的技术产品。这篇文章是考拉运营中台组最近调研微前端的一些尝试和思考
背景
项目:运营平台提效战役-大促盘货系统开发
业务:大促系统通过大促流程线上化,并与盘货、搭建、投放、促销等系统打通,实现大促商品、价格门槛约束和大促货品的应用,从而增强大促心智的一个系统。
我们的诉求是把大促系统打造成一个大促活动运营的门户站点,提供一站式的大促运营的解决方案,业务上会打通多个同级的系统。在这个基础上我们调研了微前端的一些技术方案。
微前端介绍
微前端是一种多个团队通过独立发布功能的方式来共同构建现代化 web 应用的技术手段及方法策略micro-frontends.org
微前端工程价值
- 独立开发、独立部署;
- 框架无关;
- 跨业务域复用;
- 方便功能扩展、升级;
- 便于多人协作开发;
如果微前端只存在工程上的价值是不值得大张旗鼓去做的
微前端业务价值
- 业务原子化输出;
- 业务编排整合;
应用场景
- 巨石应用的拆分-pop partner系统
- 业务编排整合-搭建&大促系统
微前端的优势可以有效的弥补当前运营中台遇到的一些痛点:
技术:考拉入园以后有很多网易技术背景下的工程,特别是中台组这边angular和vue框架实现的代码,甚至还有前后端不分离的java+angular的老工程,这些工程开发效率慢,开发体验差,没有成就感
运营:运营同事针对各种内部系统没有统一的调配入口,一次操作有可能需要在多个不同系统完成,操作效率底下
single-spa&qiankun
single-spa是现在市场上比较成熟的技术方案,以及蚂蚁基于single-spa研发的qiankun框架
single-spa:yuque.alibaba-inc.com/kaolafed-op…
import * as singleSpa from 'single-spa';
singleSpa.registerApplication('app-1', () =>
import ('../app1/app1.js'), pathPrefix('/app1'));
singleSpa.registerApplication('app-2', () =>
import ('../app2/app2.js'), pathPrefix('/app2'));
singleSpa.start();
function pathPrefix(prefix) {
return function(location) {
return location.pathname.startsWith(`${prefix}`);
}
}
我们需要注册对应的application,并且指定对应application的激活函数。同时application需要在入口文件导出相应的生命周期函数
export async function bootstrap(props) {...}
export async function mount(props) {...}
export async function unmount(props) {...}
如果简单来看的话,single-spa就是在合适的时候执行我们传入的loadFunctin, bootstarp, mount, unmount, unload方法,并抛出了一些事件
qiankun的启动调用方式和single-spa非常相似,但是在single-spa的基础上增加了一些功能
- import-html-entry
- js沙箱
- 更丰富的生命周期
- prefetch
qiankun.umijs.org/zh/guide/ge…
技术难点
1.应用隔离
- js 沙箱实现
通过proxy代理window对象,监听对应的get set方法
在应用的 bootstrap 及 mount 两个生命周期开始之前分别给全局状态打下快照,然后当应用切出/卸载时,将状态回滚至 bootstrap 开始之前的阶段,确保应用对全局状态的污染全部清零。而当应用二次进入时则再恢复至 mount 前的状态的,从而确保应用在 remount 时拥有跟第一次 mount 时一致的全局上下文
- 对象,函数劫持
setInterval、setTimeout,addEventListener,removeEventListener,appendChild
- 单实例 多实例的场景
2.样式隔离
- Shadow DOM
- CSS Module? BEM
- Dynamic Stylesheet
3.html-entry
- 获取html页面内容
- 解析成dom,script,style,entry入口文件
- 获取style的内容填充到html中
- 通过sandbox执行script代码
4.应用通信
initGloabalState,props
参考:zhuanlan.zhihu.com/p/78362028
zhuanlan.zhihu.com/p/107240132
大促系统改造方案:
主应用改造:
- 在大促系统的工程下新建了一个服务,单独用来做微服务的主应用工程
- 提供统一的吊顶服务
- 因为各个系统都维护了各自独立的登录体系,主应用暴露出login入口
- 自定义了fetch方法
- css中相对路径替换
子应用改造:
-
静态文件,接口请求支持跨域 egg-cors
-
入口文件导出生命周期
-
dll output配置 library librarytarget
-
kapp/cas 去掉 loginSuccessUrl
-
mounted 增加login组件
-
接口请求 publicpath 配置
-
静态文件 __webpack_public
path_配置
-
href 跳转替换,子应用互跳
-
独立的路由规则
-
隐藏侧边栏和顶栏
-
文件上传组件publicpath设置
-
regular nej改造
集团其他微前端的方案
阿里云 云控制台 ConsoleOs www.atatech.org/articles/15…
菜鸟 微前端的改造方案 qiankun www.atatech.org/articles/16…
飞猪 运营工作台 qiankun www.atatech.org/articles/16…
淘系 小二工作台 icestark www.atatech.org/articles/15…
支付宝 中台业务 qiankun www.atatech.org/articles/14…
技术上的痛点:巨石应用,可维护性
- 代码量达到一定量的时候,单次构建时间很长,开发&发布效率极低
- 代码库中依赖升级会影响整个应用,而代码量又非常大,导致回归成本极高
- 变成一个非常臃肿的巨石应用,完全失去灵活性,无论是多人协作还是业务接入成本都会大大增加
业务上的场景:应用的拆分和编排
- 用户端必须是「一个系统」的心智,从域名到体验
- 能够根据功能拆分成多个子应用,每个子应用独立开发独立部署
- 子应用尽量保证跟传统单页面应用一样的开发体验,不要让开发者有太多学习成本
- 所有子应用可被统一管理起来,不能无限制的泛滥
微前端生态体系?
microx microx.aliyun-inc.com/doc/hbn26z
icestark ice.alibaba-inc.com/docs/icesta…
onex bigfish.antfin-inc.com/doc/onex-ge…
什么样的模式是最佳实践?
后续规划
考拉集团内部技术栈统一
统一的配置发布平台产品,提供快速的业务整合串联能力,帮助业务提效
账号登录统一收敛
微前端子应用接入方案
包含应用 组件库 方法主应用接入方式
本地的开发工具
其他:
webpack5 module federation
webcomponent
调试
登录模式不友好
报错:ResizeObserver loop limit exceeded