qiankun接入遇到的问题
挂载节点
父应用(vue)的挂载节点(public/index.html)的id 不能与 子应用的挂载容器id相同,否则会抛错.
[qiankun] Target container with #vue-project1 not existed after vue-project1 mounted!
应修改:public/index.html中div的id,对应main.js的$mount的id也需要修改;App.vue的根元素id值(任意)
TIP
知识
vue-cli生成的项目,public/index.html中app容器
<div id="app"></div>
会被vue-template生成的模板整个替换掉,此时根元素是Vue虚拟DOM中的根元素如果是手动script:src加载的new Vue({...}), 不会替换掉html中app容器
重复注册vue-router钩子
如果vue-router的钩子(例如:beforeEach)在new Vue的生命周期(例如: create)中执行,根据子应用生命周期的执行逻辑,mount有可能会执行多次。所以也会导致vue-router的钩子注册多次,可能造成内存泄漏
// ...
let instance = null
const render = () => {
instance = new Vue({
router,
mounted() {
// 注册的路由钩子
router.beforeEach(() => {}) // ...
},
render: (h) => h(App)
}).$mount('#app')
}
// ...
// mount
export async function mount(props) {
render(props)
}
// unmount
export async function unmount() {
router.beforeHooks = [] // 清空vue-router钩子【看源码】
instance.$destroy()
}
解决:跳转业务逻辑或在子应用unmount时手动清空vue-router的前置钩子回调
router.beforeHooks = []
vue-router的base
配置后vue-router解析
base
后的path,来匹配组件
new VueRouter({
mode: 'history',
base: window['__POWERED_BY_QIANKUN__'] ? '/app1/' : '/',
routes
})
vue组件的script块打印window是原生的window?【待解决】
在主应用中加载的子应用,其js执行时,理论上讲打印的应该是Proxy
- 得打包看看,这里的逻辑了
// console.log(window)
// console.log(setInterval)
// console.log(window.setInterval === setInterval)
setInterval(() => {
console.log(1)
}, 2000)
export default {
created() {
setInterval(() => {
console.log(2)
}, 2000)
// console.log((0, eval)('window'))
console.log(window) // proxy 沙箱上下文
console.log(window.setInterval)
console.log(setInterval)
console.log(`environment: ${ process.env.VUE_APP_CUR_ENV }`)
}
}
location问题【待】
可能会破坏路由
- 解决方案?考虑劫持?
css等资源加载
css直接打包进js,即css in js
// vue.config.js
css: {
extract: false
},
axios的baseUrl
单独部署保持默认
/
,请求后端服务;
在主应用请求时需在主应用的nginx配置转发(建议),或允许所有请求跨域(不建议)
// /child-app1转发至app1的后端服务
import axios from 'axios'
if (window['__POWERED_BY_QIANKUN__']) axios.defaults.baseURL = '/child-app1'
WARNING
这块对子应用的侵入性较大。nginx转发时需要对子应用做蛮大的改造。跨域解决时需要在后端配置跨域。
本地开发:主应用中加载子应用
主应用配置
// ...
devServer: {
// ...
proxy: {
// ...
// 转发子应用服务【参考上面的axios配置】
'/child-app1': {
target: 'http://localhost:9001/', // 转发到子应用,再由子应用自个转发...(好麻烦)
pathRewrite(api) {
return api.replace(/\/child-app1/, '')
}
}
}
},
子应用配置
// ...
publicPath: isProd ? '/child-admin/' : `//${host}:${port}`, // 本地采用跨域模式,线上采用nginx转发
devServer: {
headers: {
'Access-Control-Allow-Origin': '*' // 允许跨域
},
proxy: {
// ...
'/': {
target: `http://${host}:${port}`,
bypass(req) {
if (req.headers.accept.includes('html')) return '/index.html' // 解决本地配置publicPath 404问题
}
}
}
}
// ...
子应用使用web-worker【待实验】
子应用使用web-worker,主应用无法跨域加载并执行(暂未找到解决方案)
- 解决:nginx路由转发后,子应用相对地址引用的web worker应该是可用的