以下操作,是续接之前 第四步 ——即:vite+vue3+ts+pinia+element-plus项目已完成搭建好,可以直接业务开发了
主应用技术栈:vue2+webpack+js
npm install vite-plugin-qiankun
import qiankun from 'vite-plugin-qiankun'
const packName = require('./package').name // 必须要指定当前子应用命名
// 配置NG——这个是与后台、运维约定好的,做NG转发;即主应用地址+子应用base就会直接NG转发
base: '/vitedemo',
plugins: [
// 配置qiankun
qiankun(`${packName}`, {
useDevMode: true
}),
...
]
注意点:
本地启动测试主子应用切换需要在server:{}里面添加headers: {‘Access-Control-Allow-Origin’: ‘*’ }, 解决主应用跳子应用跨域问题
server: {
headers: {
'Access-Control-Allow-Origin': '*'
},
host: '0.0.0.0',
port,
open: true,
https: false,
...
}
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
// 所有业务api接口
import api from './api'
/**
* element-plus
*/
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
// 因element-plus默认是英文,我们指定一下默认中文
import locale from 'element-plus/lib/locale/lang/zh-cn'
// 图标并进行全局注册
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
// pinia代替vuex
import pinia from './store'
// 权限控制(全局路由守卫)
import './permission'
/**
* 样式
*/
// 公共样式
import '@/assets/styles/index.scss'
// 初始化样式
import 'normalize.css'
// 统一注册 baseComponents
import baseComponentsInstall from '@/components/baseComponents/install'
// svg渲染
import SvgIcon from '@/components/SvgIcon/index.vue'
/**
* 配置qiankun
*/
import { renderWithQiankun, qiankunWindow } from 'vite-plugin-qiankun/dist/helper'
let instance: any = null
function render(props: any = {}) {
const { container } = props
instance = createApp(App)
instance.use(router)
instance.use(pinia)
// 注册全局api方法
instance.config.globalProperties.$api = api
// 注册所有图标
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
instance.component(key, component)
}
// 注册ElementPlus
instance.use(ElementPlus, {
locale // 语言设置
// size: Cookies.get('size') || 'medium' // 尺寸设置
})
// 自动注册全部本地组件
instance.use(baseComponentsInstall)
// 全局组件祖册
instance.component(
'SvgIcon',
// 如果这个组件选项是通过 `export default` 导出的,那么就会优先使用 `.default`,否则回退到使用模块的根
SvgIcon.default || SvgIcon
)
instance?.mount(container ? container.querySelector('#app') : '#app')
console.log('开始加载相关内容')
}
renderWithQiankun({
mount(props: any) {
render(props)
},
bootstrap() {
console.log('%c', 'color:green;', ' ChildOne bootstrap')
},
update() {
console.log('%c', 'color:green;', ' ChildOne update')
},
unmount(props: any) {
console.log('unmount', props)
instance.unmount()
instance._container.innerHTML = ''
instance = null
}
})
if (!qiankunWindow.__POWERED_BY_QIANKUN__) {
console.log('并不是qiankun渲染')
render()
}
import { createRouter, createWebHistory } from 'vue-router'
import { qiankunWindow } from 'vite-plugin-qiankun/dist/helper'
import Layout from '@/layout/index.vue'
import login from '@/views/login.vue'
export const constantRoutes: any = qiankunWindow.__POWERED_BY_QIANKUN__
? [
{
path: '/login',
name: 'login',
component: login,
hidden: true,
meta: {
rootPage: true,
noCache: true
}
},
{
path: '/redirect',
component: Layout,
hidden: true,
children: [
{
path: '/redirect/:path(.*)',
component: () => import('@/views/redirect.vue')
}
]
},
{
path: '',
component: Layout,
redirect: 'index',
hidden: true,
children: [
{
path: '/index',
component: () => import('@/views/index.vue'),
name: 'index',
hidden: true,
meta: { title: '首页', icon: 'monitor', noCache: true, affix: true }
}
]
}
]
: [
{
path: '/redirect',
component: Layout,
hidden: true,
children: [
{
path: '/redirect/:path(.*)',
component: () => import('@/views/redirect.vue')
}
]
},
{
path: '/login',
component: login,
hidden: true,
meta: {
noCache: true
}
},
{
path: '/404',
component: () => import('@/views/error/404.vue'),
hidden: true
},
{
path: '/401',
component: () => import('@/views/error/401.vue'),
hidden: true
},
{
path: '',
component: Layout,
redirect: 'index',
hidden: true,
children: [
{
path: '/index',
component: () => import('@/views/index.vue'),
name: 'index',
hidden: true,
meta: { title: '首页', icon: 'monitor', noCache: true, affix: true }
}
]
}
]
const router = createRouter({
history: createWebHistory(qiankunWindow.__POWERED_BY_QIANKUN__ ? '/' : '/vitedemo/'),
routes: constantRoutes,
})
export default router
import router from './router'
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
import { getToken } from '@/utils/cookies'
import { ElMessage } from 'element-plus'
import { qiankunWindow } from 'vite-plugin-qiankun/dist/helper'
import useUserStore from '@/store/modules/user'
import usePermissionStore from '@/store/modules/permission'
NProgress.configure({ showSpinner: false })
const whiteList = ['/login']
router.beforeEach((to: any, from: any, next: Function) => {
NProgress.start()
if (getToken()) {
if (to.path === '/login') {
next({ path: '/' })
NProgress.done()
} else {
if (usePermissionStore().sysMenu.length === 0) {
// 路由信息是不是组装完
useUserStore().GetInfo()
usePermissionStore().generateRoutes()
.then((accessRoutes: any) => {
accessRoutes.forEach((rout: any) => {
router.addRoute(rout) // 动态添加可访问路由表
})
next({ ...to, replace: true })
})
.catch(err => {
useUserStore().FedLogOut()
ElMessage.error(err.message || err.msg || '出现错误,请稍后再试')
next({ path: '/' })
})
} else {
// 进入页面前设置菜单
if (!qiankunWindow.__POWERED_BY_QIANKUN__) {
// 子应用单独运行,直接进入该系统
const add_routes = toRaw(usePermissionStore().sysMenu)
if (to.path === '/index') {
let lastChild =
add_routes[0]?.children?.length > 0
? add_routes[0].children[0]
: add_routes[0]
if (to.path === lastChild.path) return false
next(lastChild)
NProgress.done()
} else {
console.log('子项目的next')
next()
}
} else {
console.log('主应用进入')
next()
}
}
}
} else {
if (whiteList.indexOf(to.path) !== -1) {
next()
} else {
next(`/login`)
NProgress.done()
}
}
})
router.afterEach(() => {
NProgress.done()
})
主应用技术栈: vue2+js+element-ui
因为子应用是接口获取的,无需在单个注册
import { registerMicroApps, start } from "qiankun";
// 获取所有子应用
import childrenApp from './children.json'
// console.log('clientType=B', res)
const res = childrenApp
if (res.code == 200) {
if (window.__POWERED_BY_QIANKUN__) {
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
console.log('获取所有子应用', res.data)
const apps = res.data.children && res.data.children.map((item) => {
return {
name: item.packageName,// 微应用package.json的name字段
entry: item.entry,// 微应用访问地址,默认加载这个html页面并解析其中的js动态执行
container: '#app', // 容器名
activeRule: item.activeRule,// 激活路径,微应用路由
}
})
apps && registerMicroApps(apps, {
beforeLoad: async (app) => {
console.log('before load', app)
document.title = 'vue3+vite+ts'
},
beforeMount: [async (app) => {
console.log('before mount', app.name)
}]
})
// 启动 qiankun
start()
} else {
Element.Message.warning('加载微应用失败,将无法访问子系统')
}
new Vue({
router,
store,
render: h => h(App)
}).$mount("#app")
gitHub组件地址
gitee码云组件地址
子应用在线预览地址
基于ElementUi再次封装基础组件文档
vue3+ts基于Element-plus再次封装基础组件文档