vue3+vite+qiankun搭建微前端

采用qiankun架构搭建微前端项目,记录一下

主应用

1.安装qiankun

npm i qiankun

2.src目录新建qiankun.js文件

用于保存主应用配置

  1. name:唯一项,对应微应用的package.json的name
  2. entry:访问微应用路径端口
  3. container:加载微应用容器
  4. activeRule:匹配微应用base路由(大部分访问不了,就是路由问题)
  5. props:向微应用初始化时传值,比如传activeRule的值进行统一匹配
javascript 复制代码
import { registerMicroApps, start } from 'qiankun'
import { qiankunStore } from './store/modules/qiankun';

export function registerQiankunApps() {
  registerMicroApps(
    [
      {
        name: 'vue3-micro-app', // 微应用名称
        entry: '//192.168.0.61:9301/', // 微应用入口
        container: '#micro-app-container', // 容器ID
        activeRule: '/vue3-micro-app', // 激活规则
        props: {
          base:'/vue3-micro-app/',
        }
      },
      {
        name: 'vue3-micro-app2', // 微应用名称
        entry: '//192.168.0.61:9302/', // 微应用入口
        container: '#micro-app-container', // 容器ID
        activeRule: '/vue3-micro-app2', // 激活规则
        props: {
          base:'/vue3-micro-app2/',
        }
      }
    ],
    {
      afterMount: [app => {
        console.log('微应用加载完成');
        qiankunStore().initState()
      }]
    }
  )

  start()
}

3.配置qiankun的初始化数据和监听事件

我是放在store里面了,方便应用间响应监听,也可放到class

typescript 复制代码
import { defineStore } from 'pinia';
import { ref } from 'vue';
import { initGlobalState } from 'qiankun';

export const qiankunStore = defineStore('qiankun', () => {
  const actions  = ref<any>(null);
  const state= ref({
    token: null,
    user: null
  });


  const initState=() => {
    setGlobalState(state.value)
  }

  const initListen = () => {
    // 监听状态变化
    actions.value.onGlobalStateChange((state:any, prev:any) => {
      console.log('主应用观察状态变化:', state, prev);
    });
  };

  const init = () => {
    console.log('主应用初始化')
    actions.value=initGlobalState(state.value);
    initState();
    initListen();
  };

  //用于传值后微应用可以监听
  const setGlobalState=(...args:any) => {
    return actions.value.setGlobalState(...args);
  }
  //用于设置传值
  const setAppData=(e:any)=>{
    state.value.user=e.user;
  }

  return {
    init,
    initState,
    setGlobalState,
    setAppData
  };
});

4.配置主应用路由

建立微应用需要在主应用添加路由,可以是布局,或者空页面

javascript 复制代码
{
  path: '/vue3-micro-app/:path(.*)*', // 匹配微应用1
  name: 'app1',
  component: () => import('../layout/empty.vue'),
},
{
  path: '/vue3-micro-app2/:path(.*)*', // 匹配微应用2
  name: 'app2',
  component: () => import('../layout/empty.vue'),
}

5.组件添加容器

在empty.vue文件中,添加micro-app-container的节点,setAppData方法用于缓存切换路由的传值,在afterMount周期后才开始设值,微应用监听

xml 复制代码
<template>
  <div>
    我是外层
    <button @click="change">菜单1</button>
    <button @click="change2">菜单2</button>
    <div id="micro-app-container"></div>
  </div>
</template>

<script setup lang="ts">
import {registerQiankunApps} from '../qiankun'
import {type ComponentInternalInstance, getCurrentInstance, onMounted} from "vue";
import { qiankunStore } from '../store/modules/qiankun';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;

const change=()=>{
  proxy.$router.push({
    path: '/vue3-micro-app/about',
  });
  qiankunStore().setAppData({
    user:{
      name:'第一'
    }
  })
}

const change2=async ()=>{
  await proxy.$router.push({
    path: '/vue3-micro-app2/test',
  });
  qiankunStore().setAppData({
    user:{
      name:'第二'
    }
  })
}

onMounted(()=>{
  registerQiankunApps();
  qiankunStore().init()
})
</script>

微应用

1.安装qiankun

npm i vite-plugin-qiankun

2.修改package.json的name

"name": "vue3-micro-app",

3.修改vite.config.ts文件

与主应用注册的name一致

php 复制代码
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import qiankun from 'vite-plugin-qiankun'

export default defineConfig({
  plugins: [
    vue(),
    qiankun('vue3-micro-app', { // 与主应用注册的name一致
      useDevMode: true
    })
  ],
  base: '/',
  server: {
    host: '0.0.0.0',
    port: 9301,
    cors: true
  }
})

4.修改main.ts文件

  1. instanceRouter是主应用路由传值的话,需重新生成路由
  2. 如果不传路由,需在router/index.ts里面配置
    history: createWebHistory(qiankunWindow.__POWERED_BY_QIANKUN__ ? '/vue3-micro-app/' : '/')
javascript 复制代码
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
// import router from './router';
import store from './store';
import { qiankunStore } from './store/modules/qiankun';
import { constantRoutes } from './router';
import { createWebHistory, createRouter } from 'vue-router';


import {
    renderWithQiankun,
    qiankunWindow
} from 'vite-plugin-qiankun/dist/helper'
import type { QiankunProps } from "vite-plugin-qiankun/es/helper";

let instance: any = null;
instance = createApp(App)

if (!qiankunWindow.__POWERED_BY_QIANKUN__) {
    render({})
}

function render(props: QiankunProps = {}) {
    console.log('props', props)
    const {container} = props as any;
    instance = createApp(App)
    //主应用传入的base
    const instanceRouter = createRouter({
        history: createWebHistory(qiankunWindow.__POWERED_BY_QIANKUN__ ? props.base : '/'),
        routes: constantRoutes,
    });
    instance.use(instanceRouter);
    instance.use(store);
    instance.mount(
        container ? container.querySelector('#app') : document.getElementById('app')
    )
    qiankunStore().setActions(props)
    if (qiankunWindow.__POWERED_BY_QIANKUN__) {
        console.log('我正在作为子应用运行')
    }
}

// some code
renderWithQiankun({
    bootstrap: function (): void | Promise<void> {
        // console.log('初始化')
    },
    mount: function (props: QiankunProps): void | Promise<void> {
        render(props)
    },
    unmount: function (props: QiankunProps): void | Promise<void> {
        instance.unmount()
        instance._container = null
        instance = null;
    },
    update: function (props: QiankunProps): void {
    }
})

5.配置qiankun的监听事件

typescript 复制代码
import { defineStore } from 'pinia';
import { ref } from 'vue';

function emptyAction() {

}

export const qiankunStore = defineStore('qiankun', () => {
  const actions  = ref<any>({
    onGlobalStateChange: emptyAction,
    setGlobalState: emptyAction
  });

  const initListen = () => {
    // 监听状态变化
    actions.value.onGlobalStateChange((state:any, prev:any) => {
      console.log('1号子应用接收:', state, prev);
    });
  };

  const setActions=(actionsValue:any)=> {
    actions.value = actionsValue;
    initListen();
  }

  const setGlobalState=(...args:any) => {
    return actions.value.setGlobalState(...args);
  }

  return {
    setActions,
    setGlobalState
  };
});

6.路由配置

typescript 复制代码
import { createWebHistory, createRouter } from 'vue-router';
import type { RouteRecordRaw } from 'vue-router';

// 公共路由
export const constantRoutes: RouteRecordRaw[] = [
  {
    path: '/',
    name: 'Home',
    redirect: '/about',
  },
  {
    path: '/about',
    name: 'About',
    component: () => import('../views/index.vue')
  },
  {
    path: '/about2',
    name: 'About2',
    component: () => import('../views/about2.vue')
  }
];

/**
 * 创建路由
 */
const router = createRouter({
  history: createWebHistory(),
  routes: constantRoutes,
});

export default router;
相关推荐
雲墨款哥17 分钟前
Vue3.0 项目初始化及 Element Plus 配置实战
前端·vue.js
前端小饭桌21 分钟前
关于 Vue 3 的 ref,这些细节你了解了多少?
前端·vue.js
光影少年36 分钟前
vue3.0性能提升主要通过那几方面体现的?
前端·vue.js
江城开朗的豌豆1 小时前
路由守卫:你的Vue路由‘保安’,全局把关还是局部盯梢?
前端·javascript·vue.js
Jinxiansen02111 小时前
Vue 3 响应式核心源码详解(基于 @vue/reactivity)
前端·javascript·vue.js
清幽竹客8 小时前
vue-30(理解 Nuxt.js 目录结构)
前端·javascript·vue.js
知性的小mahua8 小时前
echarts+vue实现中国地图板块渲染+省市区跳转渲染
vue.js
weiweiweb8888 小时前
cesium加载Draco几何压缩数据
前端·javascript·vue.js
满楼、9 天前
el-cascader 设置可以手动输入也可以下拉选择
javascript·vue.js·elementui
前端fighter9 天前
Vuex 与 Pinia:全面解析现代 Vue 状态管理的进化之路
前端·vue.js·面试