出于以下几个目的,最近在用qiankun改造项目:
- 几个项目共用同一个头部,底部和登录权限系统每次更新都需要同步N次代码,再加上rc,uat两个发布分支,就是3n次,想屎的心都有了
- 之前一直写react,这个项目用vue,但总怀念使用react的时光,vue虽然更方便,但总感觉react写起来更加可控,逻辑更清晰
- 首页要做seo,可以在nuxt中使用微前端,也可以在spa中使用微前端(还没实践)
- 子项目可以独立开发,独立部署
- 主项目存放框架,子项目写业务代码,功能分开,方便代码权限控制
- 为什么不用iframe:
- url 不同步。浏览器刷新 iframe url 状态丢失、后退前进按钮无法使用。
- UI 不同步,DOM 结构不共享。想象一下屏幕右下角 1/4 的 iframe 里来一个带遮罩层的弹框,同时我们要求这个弹框要浏览器居中显示,还要浏览器 resize 时自动居中…
- 全局上下文完全隔离,内存变量不共享。iframe 内外系统的通信、数据同步等需求,主应用的 cookie 要透传到根域名都不同的子应用中实现免登效果。
- 慢。每次子应用进入都是一次浏览器上下文重建、资源重新加载的过程。
微前端的文档可以直接去官网看,不是很多,不过能满足基本需求,有问题还是去github问吧
下面说说本人在做微前端改造时遇到的一些坑,希望对大家有帮助
- 子应用导出钩子函数
- 子应用vue.config中的headers设置成可跨域请求
- output设置成library,打包成umd库格式
- 父应用使用了babel-pollfill,子应用不要在在bable-pollfill
- iconfont.js要取消样式隔离才能生效
sandbox - boolean | { strictStyleIsolation?: boolean } - 可选,是否开启沙箱,默认为 true。
当配置为 { strictStyleIsolation: true } 表示开启严格的样式隔离模式。这种模式下 qiankun 会为每个微应用的容器包裹上一个 shadow dom 节点,从而确保微应用的样式不会对全局造成影响。
- 各子应用都用到的状态放入全局(用@ice/stark-data中的store定义)
- 通过store.on监听每次更改全局状态时,都同步更新子应用的store,直接用store.get方法可以获取状态值,但无法监听状态值变化时视图同步更新,所以最好还是放在应用本身的store中进行展示
- 原则是赋值操作在各应用中同步,但修改操作只在主应用这一个地方操作,高度解耦
- 如果是选择在子应用中进行全局状态的修改,那么需要在各应用中维护所有的状态修改操作,高度耦合,导致后期的代码维护十分困难
- 一开始用的initGlobalState,发现这个是双向绑定的,即应用间要都有mutation或action,相当于要在每个子应用中写相同的store代码,不符合kiss准则,也对后期维护带来相当大困难,所以还是采用@ice/stark-data,飞冰团队的微前端通信方案
- 关于部署:
微应用的部署和原来项目的部署基本一致
- 注册时entry的路径不能和路由的base以及activeRule一致,不然会产生覆盖(如都是/cloud,则会变为去请求/cloud目录下的文件)
- 关于nginx的配置:
# 主应用
location / {
if ($request_uri ~* '/$|.html$') {
add_header Cache-Control no-store;
}
root /opt/pumpkin/fronted/;
index index.html;
try_files $uri $uri/ /index.html;
}
# cloud子应用
location /cloud/ {
if ($request_uri ~* '/$|.html$') {
add_header Cache-Control no-store;
}
alias /opt/pumpkin/fronted/;
index index.html;
try_files $uri $uri/ /index.html;
}
# mall子应用
location /mall/ {
if ($request_uri ~* '/$|.html$') {
add_header Cache-Control no-store;
}
alias /opt/pumpkin/fronted/;
index index.html;
try_files $uri $uri/ /index.html;
}
# portal子应用
location /portal/ {
if ($request_uri ~* '/$|.html$') {
add_header Cache-Control no-store;
}
alias /opt/pumpkin/fronted/;
index index.html;
try_files $uri $uri/ /index.html;
}
由于都是history的路由模式,所以:
- 每个应用配置都要加上
try_files $uri $uri/ /index.html;
否则会出现刷新报404错误- 每个子应用都要单独配置location,否则在访问/cloud,/mall,/portal时刷新会报404
- 主应用和各应用相同依赖的版本号一定要一样,不然会有莫名其妙的BUG
- 项目中使用了百度地图等组件,会出现在子应用中无法使用的情况 ,在看源码时发现子应用的document.body中添加script标签失败没报错,但无法正确添加到body中,类似性质的问题还有美洽客服的引用,pdfjs的引用两种解决方法: