介绍
qiankun 是一个基于 single-spa 的微前端实现库,旨在帮助大家能更简单、无痛的构建一个生产可用微前端架构系统。
公司有一个门户网站需要嵌入其他系统,使用iframe会有很多的兼容性问题,如果使用qiankun框架,不仅可以绕过这些iframe的坑,还可以进行很多的“骚操作”。
快速上手
qiankun官网的快速上手很简单,不是因为他们懒得写,而是引入qiankun的确是非常简单。
只需要在主应用中引入qiankun,微服务做相应的配置,就可以,下面就介绍我在项目中如何引入。
主应用
-
安装
npm install -S qiankun
-
在main.js入口文件
import { registerMicroApps, start } from 'qiankun';
const getActiveRule = (hash) => (location) => location.hash.startsWith(hash);registerMicroApps([{name: 'TPP', entry: 'http://localhost:7000/',container: '#TPP',activeRule: getActiveRule('#/TPP'),},{name: 'PTP', entry: 'http://localhost:7001/',container: '#PTP',activeRule: getActiveRule('#/PTP'),},
]);
start();
微服务配置( vue/cli3创建应用)
仅针对开发环境
qiankun会在微应用注入一个全局变量,用于针对此变量来做一些配置
if (window.__POWERED_BY_QIANKUN__) {
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
function render(props = {}) {const { container } = props;const mountPath = container ? container.querySelector('#TPPAPP') : '#TPPAPP';window.sfopenpc = new Vue({render: (h) => h(App),store,router,}).$mount(mountPath);
}
if (!window.__POWERED_BY_QIANKUN__) {render({});
}
export async function bootstrap() {console.log('[vue] vue app bootstraped');
}
export async function mount(props) {console.log('[vue] props from main framework', props);render(props);
}
export async function unmount() {window.sfopenpc.$destroy();window.sfopenpc.$el.innerHTML = '';window.sfopenpc = null;
}
- webpack配置(开发环境)
由于是不同端口,所以会出现跨域的问题,所以需要在代理服务器进行配置headers,支持微服务的Access-Control-Allow-Origin
const { name } = require('./package.json');
module.exports = {configureWebpack: {devServer: {headers: {'Access-Control-Allow-Origin': '*',},},},output: {library: `${name}-[name]`,libraryTarget: 'umd', jsonpFunction: `webpackJsonp_${name}`,},
}
效果
点击上面的菜单栏进行跳转
已经成功引入。
其他问题
主应用与微应用跳转问题
如果主应用和微应用同时使用hash
模式的话,如果不做特殊处理的话,就会出现跳转异常。
我这里简单写了一个简单的中间件,原理是在微应用的入口文件新增一个前缀处理,使得如果是qiankun框架访问的时候,自动添加路由跳转前缀的同时,点击时也会自动重定向对应的前缀。
微应用配置
import Router from 'vue-router';function handleRouter(router, prefix = '') {if (router.path) {if (router.path === '/') {router.path = `${prefix}`;} else {router.path = `${prefix}${router.path}`;}}if (router.children && router.children.length) {for (const r of router.children) {handleRouter(r, prefix);}}
}
function decorate(router, { isQiankun, prefix }) {if (isQiankun) {for (const r of router) {handleRouter(r, prefix);}}return router;
}
export default class QiankunRouter extends Router {constructor(props) {decorate(props.routes, {isQiankun: props.isQiankun,prefix: props.prefix,});super(props);this.isQiankun = !!props.isQiankun;this.prefix = props.prefix || '';if (this.isQiankun) {this.qiankunbeForeEach();}}qiankunbeForeEach() {super.beforeEach((to, from, next) => {if (this.isQiankun && !to.path.includes('/microApp')) {if (to.path === '/') {next({path: this.prefix,});} else {next({path: `${this.prefix}${to.path}`,});}}next();});}
}
- 使用QiankunRouter替换Vue-router
import Vue from 'vue';
import QiankunRouter from '../qiankun/decorateRouter';
const routes = [{path:'/',component: () => import('./qiankun/index')
}]Vue.use(QiankunRouter);
const router = new QiankunRouter({mode: 'hash',routes: vuexHoc(routes),isQiankun: !!window.__POWERED_BY_QIANKUN__,prefix: '/microApp/TPP',
});export default router;
主应用配置修改
只需要修改路由信息和qiankun主路由检测路径即可
const qiankunConfig = [{name: 'TPP',entry: 'http://localhost:7001/#/microApp/TPP',container: '#microApp',activeRule: getActiveRule('#/microApp/TPP'),}]
{path: '/microApp/*',name: '微应用',component: () => import('../views/microApp.vue'),},
微应用的弹出新窗口
弹出新窗口是可以使用相对路径,浏览器会自动获取当前的路由信息,但是如果使用主应用打开的时候打开新窗口就会异常了。
解决方案有如下:
- 封装一个跳转窗口的方法,统一使用该方法进行跳转
- 如果使用的是标签跳转新窗口的话,就不能使用相应路径,而改用URL的绝对路径替换。
js文件的预加载问题
在开发环境中,跳转路由的时候,会出现一个明显的“白屏时间”,这可能是因为请求多次导致加载时间变长,目前暂时还没有确定的解决方案,可能需要在主应用中加一个loading优化显示。