近期公司新的产品需要将之前的vue做的项目和react做的项目进行复用,我们第一事件的解决方案肯定是使用iframe,但是iframe方案有几个痛点时无法解决的: 1.弹框遮罩层只能覆盖于父级,无法遮罩全屏;2.主应用和子应用之间的通信比较麻烦,需要通过postMessage
实现。最近微服务很火,我们也准备在这个产品上实践。经过调研我们决定使用qiankun。主应用为vue + antd vue,子应用为vue + antd vue 或者 react + antd,主子应用路由模式都为hash模式。
qiankun(乾坤)是由蚂蚁金服推出的基于Single-Spa实现的前端微服务框架。
依赖下载yarn add qiankun
// main.js
import { registerMicroApps, start } from 'qiankun'
new Vue({
router,
store,
render: h => h(App),
mounted() {
// hash 路由下验证rule
const getActiveRule = hash => location => location.hash.startsWith(hash)
registerMicroApps([
{
name: 'vue-qiankun-sub', // 子应用package.json name
entry: '//localhost:8081', // 子应用本地调试地址
container: '#sub-container', // 挂载的dom节点
activeRule: getActiveRule('#/sub-vue'),
},
])
start()
},
}).$mount('#app')
路由path添加activeRule
{
path: '/sub-vue/about',
name: 'About',
component: () => import('@/views/Qiankun.vue'),
meta: {
title: '子应用',
keepAlive: true,
},
},
qiankun.vue
page-header-wrapper
#sub-container
在 src 目录新增 public-path.js,并在main.js文件中引入
if (window.__POWERED_BY_QIANKUN__) {
// eslint-disable-next-line no-undef
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__
}
入口文件 main.js 修改,根id名称最好不要和主应用重复。
let instance = null
let router = null
const render = ({ container } = {}) => {
router = routes
instance = new Vue({
router,
store,
render: h => h(App),
}).$mount(container ? container.querySelector('#vue-app') : '#vue-app')
}
// 独立运行时
if (!window.__POWERED_BY_QIANKUN__) {
render()
}
export async function bootstrap() {
console.log('vue app bootstraped')
}
export async function mount(props) {
console.log('props from main framework', props)
// 首次render在动态路由后进行执行,否则路由会报相关错误,之后则每次进入页面后执行
render(props)
}
export async function unmount() {
instance.$destroy()
instance.$el.innerHTML = ''
instance = null
router = null
}
vue.config.js
{
...other,
// qiankun 配置
devServer: {
headers: {
'Access-Control-Allow-Origin': '*',
},
port: '8081',
},
configureWebpack: {
output: {
library: `${name}-[name]`,
libraryTarget: 'umd', // 把微应用打包成 umd 库格式
jsonpFunction: `webpackJsonp_${name}`,
},
},
}
路由文件修改
let prefix = ''
if (window.__POWERED_BY_QIANKUN__) {
prefix = '/sub-vue'
}
{
path: prefix + '/about',
name: 'About',
component: () => import('@/views/About.vue'),
meta: {
title: '关于',
keepAlive: true,
},
},
主应用地址 主应用需要切换到qiankun分支
vue 子应用地址