一、主应用改造
首先需要维护一份微应用列表,里面包含了微应用的名称、入口和生效规则,若需要给子应用传递内容,可以在 props 传入对应的内容
// app.js
const apps = [{name: 'micro-vue-app3',entry: '//localhost:3013',container: '#micro-vue-app3',activeRule: '/micro-vue3-app3',props: {},},
]export default apps
有了微应用数据后,我们就开始注册微应用
// micro.jsimport { registerMicroApps, addGlobalUncaughtErrorHandler, start } from "qiankun"import apps from "./app"/** 注册微应用 */
registerMicroApps(apps, {// 微应用加载前beforeLoad: (app) => {console.log("before-load", app.name)return Promise.resolve()},beforeMount: (app) => {console.log("before mount", app)return Promise.resolve()},afterMount: (app) => {console.log("after mount", app.name)return Promise.resolve()}
})addGlobalUncaughtErrorHandler((event: Event | string) => {console.error(event)const { message: msg } = event as anyif (msg && msg.includes("died in status LOADING_SOURCE_CODE")) {console.error("微应用加载失败,请检查应用是否可运行")}
})export default start
接下来,我们在项目的入口文件中启动微前端。
import { createApp } from 'vue'
import router from './router'
import startQiankun from './micro'
import App from './App.vue'// start()
startQiankun({sandbox: {experimentalStyleIsolation: true, // 样式隔离},
})const app = createApp(App)
app.use(router)app.mount('#app')
二、子应用改造
vue3 项目创建方式分为 vue-cli 创建和 vite 创建,vue-cli 底层是 webpack,两种方式创建的项目的改造内容不太一样,接下来便为各位介绍一下改造点。
vue-cli 创建 vue3 子应用
vue.config.js 配置,需要将输出文件格式改成 umd 库格式
const { defineConfig } = require('@vue/cli-service')
const { name } = require('./package.json')
module.exports = defineConfig({transpileDependencies: true,devServer: {port: 3013,headers: {'Access-Control-Allow-Origin': '*',},},configureWebpack: {output: {library: `${name}-[name]`,libraryTarget: 'umd', // 把微应用打包成 umd 库格式},},
})
创建 public-path.ts
文件,动态设置 webpack publicPath 防止资源报错
if (window.__POWERED_BY_QIANKUN__) {// 动态设置 webpack publicPath,防止资源加载出错// eslint-disable-next-line no-undef__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__
}
main.js
需要区分独立运行还是子应用运行
import './public-path'
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'let instance = nullfunction render(props = {}) {const { container } = propsinstance = createApp(App)instance.use(router)instance.use(store)instance.mount(container ? container.querySelector('#app') : '#app')
}// 非乾坤环境
if (!window.__POWERED_BY_QIANKUN__) {render()
}
export async function bootstrap() {console.log('初次注册================')console.log('[vue] vue app bootstraped')
}export async function mount(props) {console.log('挂载子应用==============vue3-app')console.log(props)render(props)instance.config.globalProperties.$onGlobalStateChange = props.onGlobalStateChangeinstance.config.globalProperties.$setGlobalState = props.setGlobalState
}export async function unmount() {console.log('子应用卸载==========')instance.unmount()instance._container.innerHTML = ''instance = null
}
vite 创建 vue3 子应用
vite 若要用在 qiankun 微前端,需要安装 vite-plugin-qiankun
插件支持,并修改 vite.confit.ts
配置:
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import qiankun from 'vite-plugin-qiankun'// https://vitejs.dev/config/
export default defineConfig({plugins: [vue(),qiankun('vite-vue3-app3', {useDevMode: true,}),],server: {port: 7001,headers: {'Access-Control-Allow-Origin': '*',},},
})
在 main.ts
文件中,需要引入 renderWithQiankun
和 qiankunWindow
// @ts-nocheck
import { createApp } from 'vue'
import router from './router'
import App from './App.vue'
import actions from './shared/action'
import { renderWithQiankun, qiankunWindow } from 'vite-plugin-qiankun/dist/helper'let appfunction render(props) {if (props) {// 注入 actions 实例actions.setActions(props)}const { container } = propsapp = createApp(App)app.use(router)app.mount(container ? container.querySelector('#app') : '#app')
}const initQianKun = () => {renderWithQiankun({/*** 应用每次进入都会调用 mount 方法,通常我们在这里触发应用的渲染方法*/mount(props) {console.log('vite 应用挂载', props)const { container } = propsrender(props)},/*** bootstrap 只会在微应用初始化的时候调用一次,下次微应用重新进入时会直接调用 mount 钩子,不会再重复触发 bootstrap。* 通常我们可以在这里做一些全局变量的初始化,比如不会在 unmount 阶段被销毁的应用级别的缓存等。*/bootstrap() {console.log('vite-vue3 初始化')},/*** 应用每次 切出/卸载 会调用的方法,通常在这里我们会卸载微应用的应用实例*/unmount() {console.log('vite-vue3 卸载')app.unmount()},})
}qiankunWindow.__POWERED_BY_QIANKUN__ ? initQianKun() : render()
router
路由的 window 对象也需要用 qiankunWindow 去替换:
import { createRouter, RouteRecordRaw, createWebHistory } from 'vue-router'
import { qiankunWindow } from 'vite-plugin-qiankun/dist/helper'
import HelloWorld from '../components/HelloWorld.vue'
import Text from '../components/Text.vue'const routes: Array<RouteRecordRaw> = [{ path: '/', name: 'Home', component: HelloWorld, children: [{ path: 'text', name: 'Text', component: Text }] }]
const base = qiankunWindow.__POWERED_BY_QIANKUN__ ? '/vite-vue3-app3' : '/'const router = createRouter({history: createWebHistory(base),routes,
})export default router
三、Actions 通信
qiankun
内部提供了 initGlobalState
方法用于注册 MicroAppStateActions
实例用于通信,该实例有三个方法,分别是:
setGlobalState
:设置globalState
- 设置新的值时,内部将执行 浅检查,如果检查到globalState
发生改变则触发通知,通知到所有的 观察者 函数。onGlobalStateChange
:注册 观察者 函数 - 响应globalState
变化,在globalState
发生改变时触发该 观察者 函数。offGlobalStateChange
:取消 观察者 函数 - 该实例不再响应globalState
变化。
import { initGlobalState, MicroAppStateActions } from 'qiankun'const initialState = {}
const actions = initGlobalState(initialState)const actions = actions.setGlobalState({userInfo: { name: '改变用户', ssga: '2515' },age: ++currentAge.value,
})// onGlobalStateChange 第二个参数为 true,表示立即执行一次观察者函数
actions.onGlobalStateChange((state) => {console.log(state, 'state')const { userInfo, age } = statecurrUserInfo.value = userInfocurrentAge.value = age
}, true)
四、总结
本文介绍了 vue3 接入 qiankun 的方法,希望有助于个人初次上手了解。也有些人认为 vue3 结合 vite 的话,使用无界的方法会更好,有时间也会去看看如何使用,欢迎各位友好交流讨论!