乾坤微前端

640 阅读2分钟

1. 创建3个项目

web-main: 主体(基于Vue3.0)

web-config: config微应用(基于Vue2.0)

web-system: system微应用(基于Vue2.0)

通过vue-cli创建3个空项目即可

2. web-main 主体

安装qiankun: npm install qiankun

src目录下新增qiankun文件,并在mian.js中引入import './qiankun'

修改main.js

import Vue from 'vue'
import App from './App.vue'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
import router from './router'
// 引入乾坤
import './qiankun'
// 乾坤的路由跳转
import qiankunPush from './qiankun/qiankunPush'


Vue.use(ElementUI)
Vue.config.productionTip = false
// 添加乾坤的路由跳转模式
Vue.prototype.$qiankunPush = qiankunPush


new Vue({
  router,
  render: h => h(App)
}).$mount('#app')

增加3个文件appList.jsindex.jsqiankunPush.js

/**qiankun/appList.js
 * 微应用的列表
 */
export default [
  {
    name: 'web-system', // 微应用名称
    port: '8010' // 端口
  },
  {
    name: 'web-config',
    port: '8020'
  }
]
/**qiankun/index.js
 * 生成微应用列表
 * 注册微应用
 * 启动乾坤
 */
import { registerMicroApps, start } from 'qiankun'
import qiankunPush from './qiankunPush';
import appList from './appList'


// 微应用列表
const microAppList = []


// 初始化微应用列表
appList.forEach(item => {
  let temp = {
    name: item.name, // 微应用的名字
    entry: `//localhost:${item.port}/`, // 本地启动的端口
    container: '#container', // 插入App.vue中的id
    activeRule: `/${item.name}`, // 访问哪个路由进入该微应用
    props: { qiankunPush }  // 传给微应用的参数,目前只传入了一个跨应用跳转的方法
  }
  microAppList.push(temp)
})


// 注册微应用
registerMicroApps(microAppList);


// 启动乾坤
start()
/**qiankun/qiankunPush.js
 * @description 如果跨应用跳转,需要通过该方法,在每个微应用中,可以通过自己的跳转方式,如vue-router
 * @param {string} name 路由的name
 * @param {objeck} queryObj 路由后的query参数,可以为空
 */
export default function(name, queryObj) {
  // 将name转为path
  const path = name.replaceAll('_', '/')
  let query = ''
  if (queryObj && Object.keys(queryObj).length) {
    query = '?'
    Object.keys(queryObj).forEach(k => {
      query += `${k}=${v}&`
    })
  }
  window.history.pushState(null, null, `/${path}${query}`)
}

修改App.vue

<!-- App.vue,详细看web-main/src/App.vue -->
<template>
  <div id="app">
    <el-menu>
      <!-- 菜单,或者layout -->
    </el-menu>
    <!-- 微应用的容器,微应用会插入在这里,可以将该div放在layout中或需要的地方 -->
    <div id="container"></div>
  </div>
</template>

基座以上代码,详细看web-main

3. 微应用 web-system

src/public-path.js

if (window.__POWERED_BY_QIANKUN__) {
  __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__
}

src/main.js

import './public-path' // 注意需要引入public-path,qiankun.js固定的内容
import Vue from 'vue'
import App from './App.vue'
import store from './store'
import router from './router'


Vue.config.productionTip = false
// Vue实例
let vueApp = null


// render方法,处理new Vue
const render = (props = {}, Vue) => {
  const { qiankunPush, container } = props
  if (qiankunPush) {
    Vue.prototype.$qiankunPush = qiankunPush
  }
  vueApp = new Vue({
    router,
    store,
    render: (h) => h(App)
  }).$mount(container ? container.querySelector('#app') : '#app') // 如果是在基座中运行,需要在基座的container内找到#app
}


// 不是微服务启动
if (!window.__POWERED_BY_QIANKUN__) {
  render({}, Vue)
}


export async function bootstrap () {
  console.log('[vue] vue app bootstraped')
}


/**
 * 微应用启动钩子函数 加载
 * @param {object} props 基座传入的参数
 */
export async function mount (props) {
  console.log('[vue] props from main framework', props)
  render(props, Vue)
}


/**
 * 微应用启动钩子函数 卸载
 */
export async function unmount () {
  vueApp.$destroy()
  vueApp.$el.innerHTML = ''
  vueApp = null
}

src/router/index.js

const router = new VueRouter({
  base: window.__POWERED_BY_QIANKUN__ ? '/web-system/' : '/',
  mode: 'history',
  routes
})

vue.config.js

const port = 8002 // dev port 端口需要和乾坤注册同端口
const { name } = require('./package.json')


module.exports = {
  publicPath: '/web-system/',
  devServer: {
    port: port,
    open: true,
    headers: {
      // 处理子应用在基座访问时发生跨域
      'Access-Control-Allow-Origin': '*'
    }
  },
  configureWebpack: {
    output: {
      library: `${name}-[name]`,
      libraryTarget: 'umd',// 把微应用打包成 umd 库格式
      jsonpFunction: `webpackJsonp_${name}`,
    },
  }
}

4. 微应用 web-config

web-system类似