vite+vue3+ts项目搭建之集成qiankun让其成为子应用模板(vite+vue3+ts+qiankun项目)

前言

以下操作,是续接之前 第四步 ——即:vite+vue3+ts+pinia+element-plus项目已完成搭建好,可以直接业务开发了
主应用技术栈:vue2+webpack+js

集成qiankun(微前端)

1、安装vite-plugin-qiankun

npm install vite-plugin-qiankun

2、vite.config.ts文件修改,代码如下:

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,
    ...
   }

2、main.ts文件修改,完整代码如下:

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()
}

3、router.ts文件修改,完整代码如下:

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

3、全局路由守卫permission.ts文件修改,完整代码如下:

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()
})

4、其他文件修改,如下:

vite+vue3+ts项目搭建之集成qiankun让其成为子应用模板(vite+vue3+ts+qiankun项目)_第1张图片

5、到此子应用已经配置完成

主应用跳转到子应用

主应用技术栈: vue2+js+element-ui

1、main.js修改,代码如下:

因为子应用是接口获取的,无需在单个注册

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")

2、最终效果

组件地址

gitHub组件地址

gitee码云组件地址

子应用在线预览地址

相关文章

基于ElementUi再次封装基础组件文档


vue3+ts基于Element-plus再次封装基础组件文档

你可能感兴趣的:(vite+vue3项目搭建,vue3,qiankun,vite,微前端,typescript)