Micro-app总结
它借鉴了WebComponent的思想,模拟实现了ShadowDom的隔离特性,并结合CustomElement将微前端封装成一个类WebComponent组件
优点
1.每个应用都可以独立开发、独立运行、独立部署,降低耦合性
后续的维护复杂度较低
部署的灵活度更高
2.不用考虑技术框架
对兼容旧项目比较友好,可以降低开发成本
3.可扩展性好
可以在基座上新增其他子应用,以完成对整个项目的增量更新
缺点
1.基座和子应用对路由模式的选择不是完全的兼容
0.x版本中
基座用History模式,子应用可以用History,Hash
基座用Hash模式,子应用只能用Hash
Hash模式下子应用都要做相应的配置
1.x版本中
找不到相关描述,使用Hash模式基座,可以跳转Hash和History的子应用
2.静态资源的引入有时不会生效
一般情况下都会根据子应用路径自动资源路径补全
一般可生效的是引入link形式的JS,CSS;img标签
动态加载的图片不会自动补全
img标签为
[src]='';`:src=''这些都无法自动资源路径补全
3.基座和子应用之前的鉴权共享需要单独配置
子应用单独部署时,需要登录
作为子应用时,应该是基座登录一次,子应用不用再次登录
基座和子应用都为新项目时,整体架构重新设计即可
如果有一方为旧项目,新项目的鉴权可能需要为旧项目让步
4.基座和子应用的菜单展示需要单独配置
子应用单独部署时,需要展示菜单信息
作为子应用时,应该是基座展示菜单,而子应用不用
需要考虑的
基座和子应用共用一套缓存
用一套Local Storage,Session Storage
好处是鉴权可以尽量统一使用一个对象
坏处是每个系统之间的变量可能会混淆
对子应用的改造
登录
使用微前端后,基座和子应用共用一套内存,所以鉴权认证相关的本地存储使用一套即可
菜单权限
基座需要指定的路径前缀来判定当前的路由属于哪个子应用
-
根据指定路径前缀导航到基座里指定的子应用入口
以
/iamss为例,所有带/iamss的路由都会跳到这个iamss-app组件内{ path: "/iamss/:page*", name: "MILAMSS_IAMSS-LAYOUT", component: () => import("../layout/business.vue"), children: [ { path: "", name: "MILAMSS_IAMSS", component: () => import("../pages/iamss-app/index.vue"), }, ], } -
在子应用入口文件内操作子应用路由
官方给出了虚拟路由跳转的方式,此处用基座控制子应用跳转
监听路由中的params,使用microApp.router.push()跳转
导航&头部
子应用单独部署时,正常展示菜单、头部等信息
作为子应用展示时菜单、头部等信息要隐藏
使用环境变量做判断
if (window.__MICRO_APP_ENVIRONMENT__) {
console.log('我在微前端环境中')
}
退出登录
退出登录最好是在基座中控制,子应用中控制容易状态不同步,出现其他问题
如果只能在子应用中控制退出登录,可以发送消息给基座,同步信息
子应用:数据通信-子应用向主应用发送数据
部署
子应用必须支持跨域
在开发环境下,需要配置跨域
同样的,部署到服务器上也要支持跨域
需要在Nginx配置中添加相应的跨域请求头
可以参考官方文档:配置跨域
参考代码:
location / {
# 指定访问的静态文件夹
root /app/www;
# 指定index页面
index index.html index.htm;
# add_header Cache-Control;
add_header Access-Control-Allow-Origin *;
# 这个字段指定当前uri 访问的文件顺序,
# 即uri没有的话就访问uri/ 依次到index.html、404.配置这个字段的原因是angualr项目是单页应用,所以所有的uri都访问index.html
try_files $uri $uri/ /index.html =404;
}
关于路由模式
官方文档:虚拟路由系统
在0.x版本中,基座和子应用对Hash和History的路由模式有约束
但是在1.x版本中,没有相关约束了,所以基座使用Hash,子应用使用Hash或者History都可以
使用search路由模式就可以
关于预加载
官方文档:预加载
如果出现了加载缓慢的情况,可以开启预加载,预加载会在空闲时间进行
如果使用的话,一般预加载等级为2就可以
首屏加载性能优化除了基座对子应用的预加载,还可以优化子应用url对应的页面
将页面做到轻量化
遇到的问题
静态资源的引入失效
问题出现
一般情况下都会根据子应用路径自动资源路径补全
一般可生效的是引入link形式的JS,CSS;img标签
动态加载的图片不会自动补全
img标签为
[src]='';:src=''这些都无法自动资源路径补全
解决方案
- 在动态加载的路径前面加上IP端口号
- 在动态在家的路径前加上指定前缀,基座做代理
子应用部分样式高度塌陷
问题出现
使用百分比高度或者使用calc计算高度的DOM,有时候会获取不到,导致高度为0
解决方案
逐层检查,将塌陷的外部容器指定一个确定的高
Angular子应用路由跳转页面报404
问题出现
子应用内直接点击菜单跳转,页面报404,只有江苏旧系统有这个问题
是旧系统引入了error-tips库,库内部报错导致页面导航失败
解决方案
统一在基座操作子应用路由
在Angular子应用页面与基座页面切换,子应用显示异常
问题出现
从子应用页面切换到基座,再切换到子应用,子应用会显示默认的页面,而不是指定页面
路由未跳转,中间经历了一次子应用卸载和挂载
解决方案
切换到基座会销毁Micro-app组件,所以会发生卸载,再次进入子应用时,会重新挂载,是正常流程
没有进入到指定页面是因为默认展示URL的页面,如果设置了default-page则会展示default-page
跳转到指定页面需要使用Micro-app的路由,基座控制子应用跳转页面
PS: 长时间不切换页面,再次切换子应用页面,跳转失效,目前没有找到有效方法
在Angular子应用中退出登录报错:NgDevModel不存在
问题出现
子应用操作退出时,控制台报错NgDevModel不存在,只有江苏旧系统有这个问题
Session Storage中的back_url是子应用内部路由,退出登录又是子应用引入的@yz-business/manage-center的操作,如果back_url是基座的路径就没问题
解决方案
back_url由内部路由修改为基座登录页面
子应用开启导航恢复导致页面跳转错误
问题出现
在基座中控制子应用跳转页面,子应用会跳转到导航恢复指定的页面,导致页面跳转错误
解决方案
在基座控制子应用跳转和子应用导航恢复之间对比优先级,子应用导航恢复优先级
在子应用导航恢复应用处添加判断,只有不在微前端环境下且开启了导航恢复才回进行恢复
从而保证作为子应用和单独部署不出问题
在Angular子应用中导出、下载功能报错
问题出现
涉及到超链接a标签,a.download的代码在子应用中,可能都会遇到此类报错
a标签下载资源时会根据现有Window对象创建MouseEvent,即点击事件的event参数
在子应用情况下,获取的window并不是真的window,所以会报错提示转换失败
目前遇到的场景:使用打印视图导出、yz-ngx-grid的导出、ECharts的下载都会报错
Uncaught TypeError: Failed to construct 'MouseEvent': Failed to read the 'view' property from 'UIEventInit': Failed to convert value to 'Window'.
解决方案
1.使用iframe沙箱
- 使用iframe沙箱后,Angular子应用的浮窗组件:下拉框、日期选择框都会出现卡顿和部分失效的问题,视图更新问题频发
- 同样的组件在Vue中没有出现,目前公司开发的Vue项目都是由Vite构建,必须使用iframe沙箱才可以作为子应用运行
2.下载方法使用dispatchEvent
图片下载和表格导出都可以参考方法重写,因为好多都是使用的a.download()
转换a.click()的触发方式
const JPG_ELE = document.createElement('a');
JPG_ELE.download = 'print.jpg';
JPG_ELE.href = 'xxxxx'
JPG_ELE.click();
// 判断是否在Micro-app微前端环境下
if ((window as any).rawWindow && (window as any).__MICRO_APP_ENVIRONMENT__) {
// 如果是,则使用rawWindow的dispatchEvent方法触发点击事件
JPG_ELE.dispatchEvent(
new MouseEvent('click', {
bubbles: false,
cancelable: false,
view: (window as any).rawWindow,
}),
);
} else {
// 如果不是,则使用click方法触发点击事件
JPG_ELE.click();
}
3.ECharts等封装好的包
ECharts源码中做了相应的容错,但是依旧报错
Micro-app的真实Window在window.rawWindow下,ECharts获取到的类型不是Window,而是CustomWindow,导致转换失败
在ECharts中也是同样的操作,但ECharts是封装好的包,所以需要给ECharts打个补丁
我们使用patch-package为ECharts@5.3.3打补丁
这样每次安装ECharts@5.3.3的时候都会应用该补丁
如果升级了ECharts,需要重新打补丁
- 修改现有node_modules/echarts的源码
// 原来的版本,从v5.0.1到最新的v6.0.0版本,这里的window获取都这样
var $a = document.createElement('a');
$a.download = title + '.' + type;
$a.target = '_blank';
$a.href = url;
var evt = new MouseEvent('click', {
// some micro front-end framework, window maybe is a Proxy
view: document.defaultView,
bubbles: true,
cancelable: false
});
$a.dispatchEvent(evt);
window的获取修改为micro-app适配的
var $a = document.createElement('a');
$a.download = title + '.' + type;
$a.target = '_blank';
$a.href = url;
const WINDOW_MICRO_APP = window.rawWindow || document.defaultView;
var evt = new MouseEvent('click', {
// some micro front-end framework, window maybe is a Proxy
view: WINDOW_MICRO_APP,
bubbles: true,
cancelable: false
});
$a.dispatchEvent(evt);
- 安装patch-package Node14.x,Node16.x需要安装6.x
npm install patch-package@6.5.1 --save-dev
- 创建补丁文件
npx patch-package echarts
- 修改 package.json 在 package.json 中添加 postinstall 脚本:
{
"scripts": {
"postinstall": "patch-package",
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"lint": "ng lint"
}
}
5.测试补丁应用
# 验证补丁是否应用
npm run postinstall
在Angular子应用ng-zorro-antd级联选择框点击失效
问题出现
级联选择框只能选择到第一层,无法显示和点击第二层
解决方案
将zone.js的引入由组件中引入更改为main.ts中引入
建议zone.js的引入保持在main.ts中,如果报错则可以尝试放入到组件中
可以探讨的
Micro-app对Angular的支持并不是很完善
在官方的相关议题下,Angular的解决方案寥寥无几
尤其是Iframe沙箱下,视图更新情况不是很理想