最近,在做前端微应用时候用到了qiankun 框架,因此对使用中遇到的问题做了总结。
微前端其实就是:一个完整应用划分成一个主应用和一个或多个微应用,应用间相互独立,可相互通信。
qiankun的官方文档:https://qiankun.umijs.org/zh/api
当主应用是 hash 模式时,一般微应用也是 hash 模式。主应用的一级 hash 路径会分配给对应的微应用(比如 #/base1 ),此时微应用如果需要在 base 路径的基础上进行 hash 模式下的二级路径跳转(比如 #/base1/child1 ),这个场景在当前 VueRouter 的实现方式下需要自己手动实现,给所有路由都添加一个前缀即可。VueRouter 的 hash 模式下的 base 参数不支持添加 hash 路径 base。
一:使用history 模式(qiankun官方也是介绍的history模式)
① 对主应用进行改造即 安装使用qiankun
主应用项目必须安装 qiankun:npm i qiankun -S
在主应用的src文件夹下新建一个 micros 文件夹,在micros文件夹新建index.js、app.js
1.
index.js —— 主要是导出方法及生命周期钩子,用于在主应用中注册微应用
import {
registerMicroApps,
addGlobalUncaughtErrorHandler,
start
} from 'qiankun'// 微应用注册信息
import apps from './app'
// (1)registerMicroApps:包含两个参数,第一个参数是微应用的一些注册信息,第二个参数是全局的微应用生命周期钩子。:
// (2)addGlobalUncaughtErrorHandler:全局的未捕获异常处理器,微应用发生报错的时候亦可以用这个api捕捉。
// (3)start:我们用来启动qiankun的方法,包含一个参数,具体的参数用途不再详述。
registerMicroApps(apps, {
beforeLoad: (app) => {
console.log('before load=====', app.name)
return Promise.resolve()
},
afterMount: (app) => {
console.log('after mount=====', app.name)
return Promise.resolve()
}
})
addGlobalUncaughtErrorHandler((event) => {
console.error(event)
const { message: msg } = event
if (msg && msg.includes('died in status LOADING_SOURCE_CODE')) {
console.error('微应用加载失败,请检查应用是否可运行')
}
})
export default start
2.
app.js —— 主要是写一些微应用的信息
/*
* @Author: karson
* @Date: 2021-09-10 16:04:57
* @Last Modified by: karson
* @Last Modified time: 2021-09-10 16:04:57
*/
const apps = [
{
name: 'micro-app-plugin',
entry: '//localhost:8088',
container: '#plugin-container',
activeRule: '/micplugin'
}
]
// 导出的是registerMicroApps的第一个参数,是一个对象数组,其中数组每个字段的作用如下:
// (1)name:微应用的名称,后面改造微应用的时候一定要与这个name对应
// (2)entry:微应用运行的域名加端口,我用的是本地8088端口
// (3)container:启动微应用需要一个dom容器,里面就是这个dom容器的 id
// (4)activeRule:触发启动微应用的规则,当检测到url中含有activeRule的值时,将启动微应用
export default apps
3.在主应用中添加微应用 dom 容器
4、main.js 改造 —— 主要就是导入 start 方法,然后运行,启动qiankun
......
import start from '@/micros'
......
start()
②微应用改造 (微应用不需要额外安装任何其他依赖即可接入 qiankun 主应用。)
1.导出相应的生命周期钩子
改造子应用main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import '@/assets/main.css'
Vue.config.productionTip = false
// 新增:用于保存vue实例
let instance = null;
// 新增:动态设置 webpack publicPath,防止资源加载出错
if (window.__POWERED_BY_QIANKUN__) {
// eslint-disable-next-line no-undef
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
/** * 新增: * 渲染函数 * 两种情况:主应用生命周期钩子中运行 / 微应用单独启动时运行 */
function render() {
// 挂载应用
instance = new Vue({
router,
store,
render: (h) => h(App),
}).$mount("#micro-app-child");}
// #micro-app-child 对应子应用public中index.html 对应的容器id
/**
* 新增:
* bootstrap 只会在微应用初始化的时候调用一次,
下次微应用重新进入时会直接调用 mount 钩子,不会再重复触发 bootstrap。
* 通常我们可以在这里做一些全局变量的初始化,比如不会在 unmount 阶段被销毁的应用级别的缓存等。
*/
export async function bootstrap() {
console.log("VueMicroApp bootstraped");
}
/**
* 新增:
* 应用每次进入都会调用 mount 方法,通常我们在这里触发应用的渲染方法
*/
export async function mount(props) {
console.log("VueMicroApp mount", props);
render(props);
}
/**
* 新增:
* 应用每次 切出/卸载 会调用的方法,通常在这里我们会卸载微应用的应用实例
*/
export async function unmount() {
console.log("VueMicroApp unmount");
instance.$destroy();
instance = null;
}
// 新增:独立运行时,直接挂载应用
if (!window.__POWERED_BY_QIANKUN__) {
render();
}
2.改造子应用webpack (vue.config.js)
const path = require("path");
module.exports = {
devServer: {
// 监听端口
port: 8088,
// 关闭主机检查,使微应用可以被 fetch
disableHostCheck: true,
// 配置跨域请求头,解决开发环境的跨域问题
headers: {
"Access-Control-Allow-Origin": "*",
},
},
configureWebpack: {
resolve: {
alias: {
"@": path.resolve(__dirname, "src"),
},
},
output: {
// 微应用的包名,这里与主应用中注册的微应用名称一致
library: "micro-app-plugin",
// 将你的 library 暴露为所有的模块定义下都可运行的方式
libraryTarget: "umd",
// 按需加载相关,设置为 webpackJsonp_MicroAppPlugin 即可
jsonpFunction: `webpackJsonp_micro-app-plugin`,
},
},
};
3.改造子应用路由
const router = new VueRouter({
mode: 'history',
base: window.__POWERED_BY_QIANKUN__ ? '/micplugin' : '/',
routes,
scrollBehavior(to, from, savedPosition) { //设置滚动行为
......
}
})
二:使用hash模式 (与history模式一样,做如下修改)
1.主应用micros下app.js 改造
/*
* @Author: karson
* @Date: 2021-09-10 16:04:57
* @Last Modified by: karson
* @Last Modified time: 2021-09-10 16:04:57
*/
const apps = [
{
name: 'micro-app-plugin',
entry: '//localhost:8088',
container: '#plugin-container',
activeRule: '#/micplugin'
}
]
// 导出的是registerMicroApps的第一个参数,是一个对象数组,其中数组每个字段的作用如下:
// (1)name:微应用的名称,后面改造微应用的时候一定要与这个name对应
// (2)entry:微应用运行的域名加端口,我用的是本地8088端口
// (3)container:启动微应用需要一个dom容器,里面就是这个dom容器的 id
// (4)activeRule:触发启动微应用的规则,当检测到url中含有activeRule的值时,将启动微应用
export default apps
2.子应用路由改造
let prefix = '';
if(window.__POWERED_BY_QIANKUN__){
prefix = '/micplugin' // /micplugin为主应用的activeRule
}
const routes: Array<RouteConfig> = [
{
path: prefix+'/',
name: 'home',
component: Home
},
{
path: prefix+'/about',
name: 'About',
component: About
}
]
const router = new VueRouter({
mode: 'hash',
routes
});
// 这里主要是适配子应用的单独访问和继承访问
if(window.__POWERED_BY_QIANKUN__){
router.beforeEach((to, from, next) => {
if(!to.path.includes('/micplugin')){ // /micplugin为主应用的activeRule
next({path: prefix+to.path})
}else{next()}
})
}