1.安装qiankun

qiankun的官网 qiankun - qiankun   

安装过程

$ yarn add qiankun  # or npm i qiankun -S

主应用安装,子应用不需要安装;

2.主应用 qiankun 配置内容;

vue - template - admin 作为本次记录的主体;

新建 micro.js

在一下代码段中,将按照qiankun的配置模式,为主应用配置加载的主应用内容;

/**
 * qiankun 模式
 * 子系统构建主控文件
 * date:2021-11-26
 * author:yangming
 * description:子系统挂在,并通过主控文件,将子系统挂在进入主系统
*/
import axios from 'axios'
import { registerMicroApps, start, initGlobalState } from 'qiankun'
import store from '@/store/index'

// #region 加载外部配置文件
/**
 * 用于配置,项目读取的自定义配置内容
 * @returns 自定义配置内容读取
 */
async function getConfig() {
  var config = {}
  const localPath = process.env.NODE_ENV === 'development' ? '' : ''
  if (process.env.NODE_ENV === 'development') {
    // config = require(`../../../${localPath}server.config.json`)
    config = await axios.get(`../../../server.config.json`)
  } else {
    config = await axios.get(`../../${localPath}/server.config.json`)
  }
  // console.log(config)
  return config
}
// #endregion

// #region 全局监控配置

var actions = null

function GlobalState(status) {
  if (!actions) {
    actions = initGlobalState(status)
    actions.onGlobalStateChange(
      (value, prev) => {
      //   console.log(`[主应用接收到值变化 - ${actions}]:`, value, prev)
      }
    )
  } else {
    actions.setGlobalState(status)
  }
}
// #endregion

/**
 * 用户登录后,装载子系统
 * @param {*} token
 */
async function LoadingMicro() {
  // console.log('开始加载子系统')
  await getConfig().then(res => {
    var apps = res.data.MICRO_APPS
    if (apps == undefined && apps.length < 1) { return }
    /**
   * @description:  乾坤注册子应用
   * @param1 子应用配置
   * @param2 打开子应用时候触发的生命周期
   */
    registerMicroApps(apps, {
      beforeLoad: [
        function (app) {
          // console.log('[主应用] before load %c%s', 'color: green;', apps.length)
        }
      ],
      beforeMount: [
        function (app) {
          var initState = {
            userId: store.getters.userId,
            token: store.getters.token,
            route: store.getters.routeList.filter(x => x.meta.code == app.name),
            code: app.name,
            role: []
          }
          // 信息变更:全局通知
          GlobalState(initState)
          // console.log('[主应用] before mount %c%s', 'color: red;', app.name)
        }
      ],
      afterMount: [
        function (app) {
          // console.log('[主应用] afterMount mount %c%s', 'color: green;', app.name)
        }
      ],
      afterUnmount: [
        function (app) {
          // console.log('[主应用] after unmount %c%s', 'color: green;', app.name)
        }
      ]
    })
    start()
  })
}

export default LoadingMicro

并在Layout  Index.vue中的create 时 LoadingMicro这个方法,用于在客户端启动页面时,装载子应用;

server.config.json是外部配置文件,用于在系统部署后,可通过修改Json的内容,重新配置主应用的加载内容,可根据自己实际情况进行配置注册;

{
  "BASE_URL":"http://localhost:20011/api/v1",
  "MICRO_APPS":[
    {
      "name": "EMS",
      "entry": "//localhost:20009",
      "container": "#ChildSystem",
      "activeRule": "#/ems-micro",
      "props": {
        "code": "EMS",
        "name": "EMS - Test"
      }
    }
  ]
}

完成以上步骤之后,基本上已经完成了主应用的qiankun配置;

注意:由于子应用启动的时候,需要和主应用保持相对信息一致(token、时间戳),所以,在主应用的qiankun启动时,需要对全局状态进行广播,就需要在beforeMount时,更新全局通知的一致性信息,包括了token、userid等内容;(尤其,在主应用退出登录后,重新登录时,同步token,userid,未避免token不一致,导致的子应用死循环,验证token);

3.子应用配置

在主应用配置完成后,就要对子应用进行配置,配置过程中,可在子应用的main.js中直接配置,也可以自己建立一个js文件用于管理子应用配置内容;

/**
 * 新增:
 * 渲染函数
 * 两种情况:主应用生命周期钩子中运行 / 微应用单独启动时运行
 */
function render(props) {
  // console.log('子应用render的参数', props)
  props.onGlobalStateChange((state, prevState) => {
    // console.log('通信状态发生改变:', state, prevState)
    store.dispatch('authorization/microRegisterActive', state)
  }, true)
  // 挂载应用
  instance = new Vue({
    router,
    store,
    render: (h) => h(App)
  }).$mount('#micro-app')
}

// new Vue({
//   el: '#app',
//   router,
//   store,
//   render: h => h(App)
// })

// 新增:用于保存vue实例
let instance = null

// console.log(window.__POWERED_BY_QIANKUN__)
// 新增:动态设置 webpack publicPath,防止资源加载出错
if (window.__POWERED_BY_QIANKUN__) {
  // eslint-disable-next-line no-undef
  __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__
}

/**
 * 新增:
 * bootstrap 只会在微应用初始化的时候调用一次,下次微应用重新进入时会直接调用 mount 钩子,不会再重复触发 bootstrap。
 * 通常我们可以在这里做一些全局变量的初始化,比如不会在 unmount 阶段被销毁的应用级别的缓存等。
 */
export async function bootstrap(props) {
  // console.log(props)
  // console.log('初始化调用')
}

/**
 * 新增:
 * 应用每次进入都会调用 mount 方法,通常我们在这里触发应用的渲染方法
 */
export async function mount(props) {
  // console.log('触发时调用', props)
  render(props)
}

/**
 * 新增:
 * 应用每次 切出/卸载 会调用的方法,通常在这里我们会卸载微应用的应用实例
 */
export async function unmount() {
  store.dispatch('authorization/microUnApp')
  // console.log('切出或卸载调用')
  instance.$destroy()
  instance = null
}

// 新增:独立运行时,直接挂载应用
if (!window.__POWERED_BY_QIANKUN__) {
  render()
}

我是在main.js中直接进行了配置,因为内容不是很多,而且一旦配置ok,基本上不会出现变更;

请注意在render方法中的 store的 authorization/microRegisterActive 方法

该方法的目的,就是为了接收到全局状态通知的时候,用于新的数据注册控制;

 /**
 * 注册路由
 * @param {*} param0
 * @param {*} data
 */
  microRegisterActive({ commit }, data) {
    commit('setInfo', data)
    // 全局变量中如果已经存在router 则不需要再次装载,避免冲突:黄色警告
    if (state.route.length === 0) {
      var newRouter = microRegisterRouter(data.route, data.code.toLowerCase() + '-micro')
      router.addRoutes(newRouter)
      commit('setRoute', newRouter)
    }
  }

这个方法的目的就是为了在子应用的全局变量中注册,主应用的全局通知,并注册从主应用获取的子应用对应的路由信息,并注册进入子应用的router中;

完成这个配置以后,子应用中的全局变量中,就已经有了token、userid、routerArray数据了,那么子应用的相关全局信息已经健全,类似完成了登录工作;

但是,在子应用运行过程中,还需要根据业务的实际情况,对用户的活动状态进行校验时,就需要判定当前用户是否为活动用户;

如果不需要如此业务进行支撑,就需要保证子应用在脱离主应用的情况下,无法独立运行;

因为我们的request的请求过程中,必须要带入token这个头参数,这样才能保证子应用的微服务可以通过与主应用的微服务进行校验通讯,否则访问非法;

同样的,在主应用的全局通讯过程中,还可以将子应用的code传递过来,便于日志记录过程中,区别日志来源是那个子系统。如果,在使用子应用的横向扩展时,也可以根据code进行编号处理,便于区分相关操作的渠道;(这个就不展示了,需要自己实现);

4.部署

在完成以上配置后,主应用和子应用的启动过程和开发过程基本上,就已经满足开发使用了。

然而,在部署过程中,可能就会遇到一些红色问题;

例如:css、js文件找不到。

这个问题,就需要在子应用的vue.config.js中进行配置,主要配置内容就是publicPath的路径变更

publicPath: process.env.NODE_ENV === 'development' ? '/' : '/microApps/ems-micro'

这个配置路径的解释:判断当前是否为开发模式,如果是开发模式,那么publichPath的路径就是‘/’ ,而当前模式不是开发模式时,就需要将publicPath更改为'/microApps/ems-micro'

如此才能让部署过程中,子应用的路径正确;

microApps/ems-micro 是物理路径,也就是在主应用的 dlist 中 创建microApps文件夹,并在 microApps文件夹中创建ems-micro文件夹,用于存放,ems-micro工程的dlist文件;

注意:publicPath的部署路径,必须和文件创建的路劲一致,否则就会报错;

5.前端同一端口部署说明

1.文件夹结构说明

在部署过程中,需要将主应用与子应用使用一个端口的配置如下: 

在开发过程中 Entry 可以为localhst:00001这种模式,如果要发布,则要将子应用的路径改为绝对路径。且前后必须,加入 / , 例如:/mes-micro/

"MICRO_APPS":[
     {
        "name": "MES",
        "entry": "/mes-micro/", // 与主应用的文件管理器中的路径一致
        "container": "#ChildSystem",
        "activeRule": "#/mes-micro",
        "props": {
          "title":"生产管理系统",
          "code": "MES",
          "name": "MES - System",
          "userId": null,
          "token":null,
          "route": null
        }
      }    
    ]

所谓路径一致,就是要在如下模式:

红色框选中,就是子应用的vue发布代码;

2.子应用配置,需要在vue.config.js中配置publicPath

publicPath: process.env.NODE_ENV === 'development' ? '/' : '/mes-micro/',
  

 多次出现 mes-micro 的地方必须一致,否则就会无法加载

以上就是我在使用qiankun的过程记录;仅供参考;

Logo

前往低代码交流专区

更多推荐