腾讯无界
无界集成中可能出现的问题总结主要包括:
- 跨域问题:当无界微应用尝试访问 Next.js 项目的 API 时,由于安全策略(同源策略),可能会遇到跨域错误。解决办法是在 Next.js 的
next.config.js
文件中配置headers
,允许所有来源的请求。 - window.parent问题:在子应用中使用 iframe 时,窗口对象可能被代理,导致获取不到真正的子应用上下文。解决此问题需正确处理 window.parent 对象的引用。
- message显示问题:某些情况下,如在 AntdV 等库中,关闭并重新打开子应用后,message 提示可能不显示。这可能是由于子应用生命周期管理的影响,应避免过度修改子应用的生命周期。
- 图片路径问题:动态插入的相对 URL 图片可能不会自动转换成绝对路径,这时需要手动处理图片资源的公共路径。
- 窗口对象获取:在某些模式下,子应用的 window 对象是一个代理对象,需要使用特定方法(如
window.WUJIE_RAW_WINDOW
)获取真实对象。 - 路由管理异常:特别是涉及路由切换时,如果使用了iframe,可能会影响浏览器的前进和后退操作,因为每个iframe都有独立的路由栈。
- 官网解释的常见问题
1、请求资源报错
2、第三方包已经引入,使用时报错
3、子应用的字体没有生效
4、冒泡系列组件(比如下拉框)弹出位置不正确
5、子应用处理异步处理事件时,e.target 变成了 wujie-app
6、css 样式内部的相对地址相对的是主应用的域名
7、子应用使用 module federation 引用远程模块报错
8、子应用 iframe 初始化时加载、执行了主应用的资源
9、子应用 window 是一个代理对象,如何获取子应用的真实对象
10、DOMException: Blocked a frame with origin from accessing a cross-origin frame 报错
11、子应用的相对地址图片没有替换成绝对地址
12、vite4 子应用样式切换丢失
阿里乾坤
主子应用样式相互影响
各个应用样式隔离 这个问题乾坤框架做了一定的处理,在运行时有一个sandbox的参数,默认情况下沙箱可以确保单实例场景子应用之间的样式隔离,但是无法确保主应用跟子应用、或者多实例场景的子应用样式隔离。如果要解决主应用和子应用的样式问题,目前有2种方式:
- 在乾坤种配置 { strictStyleIsolation: true } 时表示开启严格的样式隔离模式。这种模式下 qiankun 会为每个微应用的容器包裹上一个 shadow dom 节点,从而确保微应用的样式不会对全局造成影响。但是基于 ShadowDOM 的严格样式隔离并不是一个可以无脑使用的方案,大部分情况下都需要接入应用做一些适配后才能正常在 ShadowDOM 中运行起来,这个在 qiankun 的 issue 里面有一些讨论和使用经验。
- 人为用 css 前缀来隔离开主应用和子应用,在组件层面用 css scoped进行组件层面的样式区分,在 css框架层面可以给css组件库加上不同的前缀,比如文档中的 antd 例子:配置 webpack 修改 less 变量
代码语言:javascript
{
loader: 'less-loader',
+ options: {
+ modifyVars: {
+ '@ant-prefix': 'yourPrefix',
+ },
+ javascriptEnabled: true,
+ },
}
b. 配置 antd ConfigProvider
import { ConfigProvider } from 'antd';
export const MyApp = () => (
<ConfigProvider prefixCls="yourPrefix">
<App />
</ConfigProvider>
);
应用间通信
- localStorage/sessionStorage
- 通过路由参数共享
- 官方提供的 props
- 官方提供的 actions
- 使用vuex或redux管理状态,通过shared分享
具体实现参考这篇文章 qiankun的五种通信方式
qiankun 实现 keep-alive 需求
子项目 keep-alive 其实就是想在子应用切换时不卸载掉,仅仅是样式上的隐藏(display: none),这样下次打开就会更快。
但是 keep-alive 需要谨慎使用,同时加载并运行多个子应用,这将会增加 js/css 污染的风险。
产品那边其实当时是有提出这个需求的,当时第一时间想到的是借助 qiankun 的 loadMicroApp 函数来手动加载和卸载子应用。但是公司的项目主应用嵌入了十几个子应用,想到需要一个个处理,以及手动加载和卸载子应用所可能带来的一些边界问题处理,后面直接说这个需求不好实现。之后也就暂时搁置了
具体解决方案可以看 qiankun issues 里所给出的
路由跳转问题
在子应用中是没有办法通过 <router-link>
或者用 router.push/router.replace
直接跳转的,因为这个 router 是子应用的路由,所有的跳转都会基于子应用的 base 。当然了写 <a>
链接可以跳转过去,但是会刷新页面,用户体验并不好。
这里可以采用以下两种方式:
- 将主应用的路由实例通过 props 传给子应用,子应用用这个路由实例跳转。
- 路由模式为 history 模式时,通过 history.pushState() 方式跳转
这里我把他封装为了一个常用方法
代码语言:javascript
/**
* 微前端子应用路由跳转
* @param {String} url 路由
* @param {Object} mainRouter 主应用路由实例
* @param {*} params 状态对象:传给目标路由的信息,可为空
*/
const qiankunJump = (url, mainRouter, params) => {
if (mainRouter) {
// 使用主应用路由实例跳转
mainRouter.push({ path: url, query: params })
return
}
// 未传递主应用路由实例,传统方式跳转
let searchParams = '?'
let targetUrl = url
if (typeOf(params) === 'object' && Object.keys(params).length) {
Object.keys(params).forEach(item => {
searchParams += `${item}=${params[item]}&`
})
targetUrl = targetUrl + searchParams.slice(0, searchParams.length - 1)
}
window.history.pushState(null, '', targetUrl)
}
适配vue-pdf 报错
找到vue-pdf的依赖包下的vuePdfNoSss.vue
代码语言:javascript
//找到vue-pdf的依赖包下的vuePdfNoSss.vue
<style src="./annotationLayer.css"></style>
<script>
import componentFactory from './componentFactory.js'
if ( process.env.VUE_ENV !== 'server' ) {
var pdfjsWrapper = require('./pdfjsWrapper.js').default;
var PDFJS = require('pdfjs-dist/es5/build/pdf.js');
if ( typeof window !== 'undefined' && 'Worker' in window && navigator.appVersion.indexOf('MSIE 10') === -1 ) {
// 注释原本的引入方法
// var PdfjsWorker = require('worker-loader!pdfjs-dist/es5/build/pdf.worker.js');
var PdfjsWorker=require('pdfjs-dist/es5/build/pdf.worker.js');
PDFJS.GlobalWorkerOptions.workerPort = new PdfjsWorker();
}
var component = componentFactory(pdfjsWrapper(PDFJS));
} else {
var component = componentFactory({});
}
export default component;
</script>
修改项目的配置文件vue.config.js
chainWebpack: (config) => {
config.module
.rule('worker')
.test(/.worker.js$/)
.use('worker-loader').loader('worker-loader')
.options({
inline: true,
fallback: false
}).end();
}
主项目和子项目部署到一起,子项目部署到二级目录(不占用这么多端口)
因为客户方的要求,可能有时候不允许服务器开太多的端口,因此需要把主应用和微应用部署到一起,公用一个端口。
主项目和子项目部署到一起,子项目部署到二级目录
qiankun在子应用中引入百度地图时报错解决
因为qiankun会把静态资源的加载拦截,改用fetch方式获取资源,所以要求这些资源支持跨域,这里我们使用qiankun提供的 excludeAssetFilter 将其加入白名单放行。
- excludeAssetFilter -
(assetUrl: string) => boolean
- 可选,指定部分特殊的动态加载的微应用资源(css/js) 不被 qiankun 劫持处理
修改主应用 start 方法
代码语言:javascript
// 启动微前端
if (!window.qiankunStarted) {
window.qiankunStarted = true
start({
singular: false,
excludeAssetFilter: (assetUrl) => {
// 过滤baidu
const wihiteWords = ['baidu']
if (wihiteWords.includes(assetUrl)) {
return true
}
return wihiteWords.some(w => {
return assetUrl.includes(w)
})
}
})
}
其他一些常见问题可见于 qiankun官网
总的来说,微前端确实解决了一些项目中的痛点,但是切记微前端不是银弹,老旧项目带来的迁移成本,不同项目技术栈的兼容与边界问题处理,因为没有迫切的需求而接入微前端,只会带来额外的负担,很多时候,iframe 其实就很够用了。
参考链接:blog.csdn.net/BradenHan/a… cloud.tencent.com/developer/a…