微前端乾坤(qiankun)初尝试

介绍

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',
        // 主应用使用的hash模式
        activeRule: getActiveRule('#/TPP'),
      },
      {
        name: 'PTP', 
        entry: 'http://localhost:7001/',
    	// 主应用挂载的节点
        container: '#PTP',
        // 主应用使用的hash模式
        activeRule: getActiveRule('#/PTP'),
      },
    ]);
    start();
    

微服务配置( vue/cli3创建应用)

仅针对开发环境

  • 微服务入口文件

qiankun会在微应用注入一个全局变量,用于针对此变量来做一些配置

if (window.__POWERED_BY_QIANKUN__) {
// 如果是正常访问,则为undefined,如果是qiankun访问,则为true
  __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
function render(props = {}) {
	/** 
	props 参数
	container:  主应用挂载微应用的节点
	mountParcel: ƒ ()
	name: "TPP" 微应用name
	onGlobalStateChange: ƒ onGlobalStateChange(callback, fireImmediately)
	setGlobalState: ƒ setGlobalState()
	singleSpa
	*/
  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({});
}
// qiankun的生命周期回调
export async function bootstrap() {
  console.log('[vue] vue app bootstraped');
}
export async function mount(props) {
  console.log('[vue] props from main framework', props);
  // 如果qiankun框架引入,则会在页码加载完成之后调用此方法
  render(props);
}
export async function unmount() {
  window.sfopenpc.$destroy();
  window.sfopenpc.$el.innerHTML = '';
  window.sfopenpc = null;
  // router = 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', // 把微应用打包成 umd 库格式,不配置的话,主应用导入会报错
    jsonpFunction: `webpackJsonp_${name}`,
  },
}

效果

在这里插入图片描述
点击上面的菜单栏进行跳转
在这里插入图片描述
已经成功引入。

其他问题

主应用与微应用跳转问题

如果主应用和微应用同时使用hash模式的话,如果不做特殊处理的话,就会出现跳转异常。
我这里简单写了一个简单的中间件,原理是在微应用的入口文件新增一个前缀处理,使得如果是qiankun框架访问的时候,自动添加路由跳转前缀的同时,点击时也会自动重定向对应的前缀。

微应用配置
  • 中间件QiankunRouter
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);
    }
  }
}

// eslint-disable-next-line no-unused-vars
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();
    }
  }

  // eslint-disable-next-line no-unused-vars
  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
/* eslint-disable no-unused-vars */
import Vue from 'vue';
// import router from 'Vue-router'
import QiankunRouter from '../qiankun/decorateRouter';
// 路由信息
const routes = [{
	path:'/',
	component: () => import('./qiankun/index') 
}]

Vue.use(QiankunRouter);
const router = new QiankunRouter({
  mode: 'hash',
  routes: vuexHoc(routes),
  // eslint-disable-next-line no-underscore-dangle
  isQiankun: !!window.__POWERED_BY_QIANKUN__,
  // 路由跳转前缀
  prefix: '/microApp/TPP',
});

export default router;
主应用配置修改

只需要修改路由信息和qiankun主路由检测路径即可

  • qiankun主路由检测路径
const qiankunConfig = [{
    name: 'TPP',
    // 访问微应用的跳转首页路径 新增#/microApp/TPP,匹配的是原来的/
    entry: 'http://localhost:7001/#/microApp/TPP',
    container: '#microApp',
    // 主应用hash配置前缀
    activeRule: getActiveRule('#/microApp/TPP'),
  }]
  • 路由信息
  {
  	// 给微应用配置一个固定前缀
    path: '/microApp/*',
    name: '微应用',
    component: () => import('../views/microApp.vue'),
  },

微应用的弹出新窗口

弹出新窗口是可以使用相对路径,浏览器会自动获取当前的路由信息,但是如果使用主应用打开的时候打开新窗口就会异常了。
解决方案有如下:

  1. 封装一个跳转窗口的方法,统一使用该方法进行跳转
  2. 如果使用的是<a>标签跳转新窗口的话,就不能使用相应路径,而改用URL的绝对路径替换。

js文件的预加载问题

在开发环境中,跳转路由的时候,会出现一个明显的“白屏时间”,这可能是因为请求多次导致加载时间变长,目前暂时还没有确定的解决方案,可能需要在主应用中加一个loading优化显示。

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值