1、使用原因

  • 项目越来越大,运行打包较慢(主要)。目前的前端项目使用vue架构,页面已经超过了100张,打包越来越慢,虽然已经进行了压缩处理,但是修改一个地方,重新编译全部,电脑有点带不动了。

  • 多种业务逻辑混杂在一个系统,有时候只需要修改某个业务模块的代码,但是却要运行全部功能模块才能进行修改。

2、qiankun 特点https://qiankun.umijs.org/zh/guide

  • 技术栈无关,前端的代码框架没有限制

  • 独立开发,独立部署。升级可以只针对某个微服务进行升级

主要参考文档

https://blog.csdn.net/qq_33396780/article/details/110694871

https://blog.csdn.net/u013655559/article/details/107527135

我的理解是前端微服务具有一个主服务,多个微服务,类似于后端的微服务架构。

在我的项目中dmp_web是主服务,dmp_ai是微服务。

主服务修改配置

(1)主服务先安装qiankun插件

npm i qiankun -S

(2)主服务的页面入口App.vue

<div id="app">
    <router-view />
    <!-- 微服务挂载dom -->
    <div id="appContainer" />
</div>

(3)主服务main.js配置

// 引入qiankun微服务,注册ai模块
import { registerMicroApps, start, initGlobalState } from 'qiankun'
// 用了getActiveRule来完成匹配,getActiveRule函数通过传入当前 location 作为参数,然后根据函数返回数值来看,若返回值为 true 时则表明当前子应用会被激活,则去调用entry入口配置
const getActiveRule = (hash) => (location) => location.hash.startsWith(hash)

const propData = {
  store: store,
  router: router
}


let testData = {
  opt: ''
}
const actions = initGlobalState(testData)
// 主项目项目监听和修改(在项目中任何需要监听的地方进行监听)
actions.onGlobalStateChange((state, prev) => {
  // state: 变更后的状态; prev 变更前的状态
  console.log('改变前的值 ', prev)
  console.log('改变后的值 ', state)
})
// 将actions对象绑到Vue原型上,为了项目中其他地方使用方便
Vue.prototype.$actions = actions

// 微服务模块
const apps = [
  {
    name: 'dmp_ai', // AI模块 应用名字
    entry: process.env.NODE_ENV === 'production' ? '/dmp_ai/' : '//localhost:8890', // 入口
    container: '#appContainer', // 容器名(此项目页面中定义的容器id,用于把对应的子应用放到此容器中)
    activeRule: getActiveRule('#/dmp_ai/'), // 激活的路径
    props: propData // 传参
  }
]
registerMicroApps(apps) // 注册应用
start({
  prefetch: false // 取消预加载
}) // 开启

微服务配置修改

(1)微服务main.js修改

// qiankun配置
let instance = null
function render(props) {
  instance = new Vue({
    router,
    store, // 子应用自己的store
    data() {
      return {
        parentStore: props && props.store ? props.store : null, // qianKun模式下,主服务的store传给子服务
        parentRouter: props && props.router ? props.router : [] // qiankun模式下启动时,把主服务的路由传给子服务
      }
    },
    render: h => h(App)
  }).$mount('#devApp') // 这里是挂载到自己的html中  基座会拿到这个挂载后的html 将其插入进去
}


if (window.__POWERED_BY_QIANKUN__) { // 动态添加publicPath
  __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__
  router.beforeEach((to, from, next) => {
    if (!to.path.includes('/dmp_ai')) {
      next({
        path: '/dmp_ai/' + to.path  // 请求的路径如果是qiankun模式下动态的增加前缀dmp_ai前缀
      })
    } else {
      next()
    }
  })
}
if (!window.__POWERED_BY_QIANKUN__) { // 默认独立运行
  render()
}
// 父应用加载子应用,子应用必须暴露三个接口:bootstrap、mount、unmount
// 子组件的协议就ok了
export async function bootstrap(props) {


}


export async function mount(props) {
  // 加了true之后,会自动调取前面这个回调方法,这样可以拿到主应用(基座)修改的值
  props.onGlobalStateChange((state, prev) => {
    // state: 变更后的状态; prev 变更前的状态
    console.log(state, prev)
  }, true)


  Vue.prototype.$onGlobalStateChange = props.onGlobalStateChange
  Vue.prototype.$setGlobalState = props.setGlobalState
  console.log(props)
  const username = props.store.getters.username
  const btn_permission = props.store.getters.permissions
  // 把用户名称赋值给ai服务的store,用于鉴权
  store.commit('user/SET_NAME', username)
  // 把按钮权限设置给ai服务的store
  store.commit('user/SET_PERMISSION', btn_permission)
  render(props)
}


export async function unmount(props) {
  console.log('销毁子服务=================》')
  instance.$destroy()
}

(2)微服务vue.config.js修改

// 打包用
publicPath: process.env.NODE_ENV === 'production' ? '/dmp_ai/' : '/',
devServer: {
    port: 8090,//这里的端口是必须和父应用配置的子应用端口一致
    headers: {
      // 因为qiankun内部请求都是fetch来请求资源,所以子应用必须允许跨域。基座 https://dev.portal.com/ 获子应用a的资源 https://dev.monitor.com/a的资源 ,根据浏览器同源策略(浏览器采用同源策略,禁止页面加载或执行与自身来源不同的域的任何脚本)
      'Access-Control-Allow-Origin': '*'
    },
},
configureWebpack: {
    name: name,
    output: {
      //资源打包路径
      library: 'vueApp',
      libraryTarget: 'umd'}
  }

(3)微服务路由修改route.js

let prefix = '/'
// 如果是通过主服务过来的,有前缀dmp_ai
if (window.__POWERED_BY_QIANKUN__) {
  prefix = '/dmp_ai/'
}

主服务,微服务的路由都是hash模式

官网说:主应用和微应用都是 hash 模式,主应用根据 hash 来判断微应用,则不用考虑这个问题。

页面跳转:

主应用跳转微应用

this.$router.push({ path: '/dmp_ai/xx' })

实际上hash模式跳转的时候,找不到dmp_ai开头的任何配置,所以会转404,所以在生成路由的时候,修改动态路由生产规则里的404配置,除了dmp_ai外的所有页面再转404

accessedRoutes.push({ path: '^dmp_ai.*', id: '99999', redirect: '/404', hidden: true })

微应用跳转主应用

this.$root.parentRouter.push('/portal')

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐