Skip to content
微信公众号

qiankun进阶

对于qiankun框架来说已经提供了很多微前端的基础能力,但是在中后台管理系统复杂场景的也有很多,这时候就需要qiankun提供一些进阶的能力来帮助开发者去更好的开发。

提取公共库

提取公共依赖可以参考:qiankun 如何提取出公共的依赖库

  • qiankun不建议共享依赖,担心原型链污染等问题。 single-spa推荐共享大型依赖,需要小心处理污染问题,它们都是推荐使用webpack的external来共享依赖库。
  • 我们也推荐共享大的公共依赖,也是使用webpack的external来共享依赖库,不过是每个子应用加载时都重复再加载一次库,相当于节省了相同库的下载时间,也保证了不同子应用间不会产生原型链污染,属于折中的方案。

页签切换优化(keep-alive)

在经典的后端管理系统中,打开一个新页面都会对应打开一个页签,切换回上一个打开的页签并保留原页签的缓存能力是较常见的需求。但qiankun方案在自动匹配加载一个子应用时,会卸载上一个子应用,原本的数据也会丢失,无法实现缓存。对于此问题,我们将基于路由自动匹配加载微应用的方式改为调用api手动加载,同时缓存子应用实例及页面,完美解决页签切换过程中数据丢失问题。

本地缓存封装

在qiankun微前端技术方案中,各微应用浏览器的本地存储状态是共享的,存在各个业务微应用本地缓存的key值同名隐患,容易引起各业务微应用操作本地存储时数据覆盖、误删除等问题。为了解决这个问题,我们使用代理模式对浏览器本地缓存进行处理,同时新增缓存api,默认为业务微应用统一加上应用唯一标识作为本地存储的key 值前缀,避免同名问题。

js
 const storageProxy = new Proxy(window.localStorage, {
            set: (target: typeof localStorage, prop: PropertyKey, value: any, receiver) => {
                if (typeof prop === "string") {
                    const oldValue = target[prop];
                    if (!equal(oldValue, value)) {
                        return Reflect.set(target, prop, value, receiver);
                    }
                }
                return false;
            },
            get: (target, prop, receiver) => {
                // 在执行localstorage.setItem方法时,会出现报错
                // 发现仅仅一步Reflect.get(target, prop);是不行的
                // 所以单独每个方法拿出来重写了一下
                if (prop === "setItem") {
                    return function (key: string, value: any) {
                        return Reflect.set(target, `${namespace}.${key}`, value);
                    };
                } 
                return Reflect.get(target, prop, receiver);
            },
        });

应用通信扩展

qiankun微前端自带的一个实现全局通信的api是initGlobalState,使用不够灵活,在微应用中只能修改已存在的一级属性,并且qiankun会在下一个大版本移除此api。针对此情况,可以扩展新的通信方式,一是通过vuex的方式,在基座主应用维护一个全局的common模块,下发到子应用中,作为各应用可访问的公共状态,实现数据共享;二是使用eventBus的方式,在基座主应用定义并下发eventBus实例,通过发布订阅者模式实现各应用间事件的通信。以上两种方式可以较好的实现项目开发中各种数据通信需求。

子应用嵌套

子应用嵌套即子应用可以嵌入其它子应用。在qiankun中子应用是可以独立运行的,运行后登录页、Layout基础模块包括菜单、注销,还能正常开发和使用。这个时候就需要把登录页、Layout、App三个模块迁移到common模块,通过引入的方式,然后根据window.__POWERED_BY_QIANKUN__判断当前运行环境是否独立运行做相对应的逻辑处理。

子应用并行

子应用并行即子应用同时展示,将当前子应用放到另外一个子应用进行展示,同时展示多次,可能是同一个页面,也可能是不同的页面。

注意子应用共存时,Vue子应用需要使用abstract路由,React使用MemoryRouter

vue
export const router = new VueRouter({
  mode: 'hash',
  base: process.env.BASE_URL,
  routes,
})

export const abstractRouter = new VueRouter({
  mode: 'abstract',
  base: process.env.BASE_URL,
  routes,
})

function render(props?: Prop) {
  let container: null | HTMLElement = null
  if (props && props.container) {
    container = props.container
  }
  const vueContainer = container ? (container.querySelector('#app') as Element) : '#app'

  if (props?.path) {
    routerInstance = abstractRouter
  } else {
    routerInstance = router
  }

  instance = new Vue({
    router: routerInstance,
    pinia: createPinia(),
    render: (h) => h(App),
  }).$mount(vueContainer)

  if (props?.path) {
    routerInstance.push(props.path)
  }
}

Released under the MIT License.