vue+qiankun微前端实践

qiankun(https://qiankun.umijs.org/zh/guide/getting-started)基座也可以用多种脚手架搭建(此处以vue2.x 为例):

vue-cli搭建vue2.x 项目,然后安装qiankun:

$ yarn add qiankun  # or npm i qiankun -S

基座配置:

我们将子应用的配置都放在:main/src/micro-app.js下:

const microApps = [
    {
      name: 'sub-vue1',
      entry: '//localhost:7777/',
      activeRule: '/sub-vue1',
      container: '#subapp-viewport', // 子应用挂载的div
      props: {
        routerBase: '/sub-vue1' // 下发路由给子应用,子应用根据该值去定义qiankun环境下的路由
      }
    },
    {
      name: 'sub-vue2',
      entry: '//localhost:7788/',
      activeRule: '/sub-vue2',
      container: '#subapp-viewport', // 子应用挂载的div
      props: {
        routerBase: '/sub-vue2'
      }
    }
  ]

export default microApps

然后在src/main.js中引入,qiankun这个库只需要在基座引入,在main.js中注册子应用,为了方便管理

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import {
  registerMicroApps,
  addGlobalUncaughtErrorHandler,
  start
} from 'qiankun'
import microApps from './micro-app'
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
import Element from 'element-ui'

Vue.config.productionTip = false

Vue.use(Element, {
  size: 'medium' // set element-ui default size
})

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

/**
 * 注册微应用
 * 第一个参数 - 微应用的注册信息
 * 第二个参数 - 全局生命周期钩子
 */
registerMicroApps(microApps, {
  // qiankun 生命周期钩子 - 微应用加载前
  beforeLoad: app => {
    NProgress.start()
    console.log('before load app.name====>>>>>', app.name)
  },
  beforeMount: [
    app => {
      console.log('[LifeCycle] before mount %c%s', 'color: green;', app.name)
    }
  ],
  afterMount: [
    app => {
      // 加载微应用前,进度条加载完成
      NProgress.done()
      console.log('[LifeCycle] after mount %c%s', 'color: green;', app.name)
    }
  ],
  afterUnmount: [
    app => {
      console.log('[LifeCycle] after unmount %c%s', 'color: green;', app.name)
    }
  ]
})

/**
 * 添加全局的未捕获异常处理器
 */
addGlobalUncaughtErrorHandler(event => {
  console.error(event)
  const { message: msg } = event
  // 加载失败时提示
  if (msg && msg.includes('died in status LOADING_SOURCE_CODE')) {
    this.$message({
      showClose: true,
      message: '微应用加载失败,请检查应用是否可运行',
      type: 'error'
    })
  }
})

// 导出 qiankun 的启动函数
start()

App.vue中,需要声明micro-app.js配置的子应用挂载div(注意id一定要一致),以及基座布局相关的,大概这样:

<template>
  <div id="main-app">
    <div id="nav">
      <router-link to="/">Home</router-link> |
    </div>
    <router-view/>
    <div id="subapp-viewport"></div>
  </div>
</template>


子应用配置

一、vue子应用

用Vue-cli新建一个sub-vue1的子应用(这里演示完全独立运行的3个项目),子应用的名称最好与父应用在src/micro-app.js中配置的名称一致(这样可以直接使用package.json中的name作为output)。

  1. 新增vue.config.js,devServer的端口改为与主应用配置的一致,且加上跨域headersoutput配置。

        

// package.json的name需注意与主应用一致
const { name } = require('./package.json')

module.exports = {
  configureWebpack: {
    output: {
      library: `${name}-[name]`,
      libraryTarget: 'umd',
      jsonpFunction: `webpackJsonp_${name}`,
    }
  },
  devServer: {
    port: process.env.VUE_APP_PORT, // 根目錄新建.env中VUE_APP_PORT=7777,与父应用的配置一致
    headers: {
      'Access-Control-Allow-Origin': '*' // 主应用获取子应用时跨域响应头
    }
  }
}

2、新增src/public-path.js

;(function () {
  if (window.__POWERED_BY_QIANKUN__) {
    if (process.env.NODE_ENV === 'development') {
      // eslint-disable-next-line
      __webpack_public_path__ = `//localhost:${process.env.VUE_APP_PORT}${process.env.BASE_URL}`
      return
    }
    // eslint-disable-next-line
    __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__
  }
})()

3、src/router/index.js改为只暴露routes,new Router改到main.js中声明。

4、改造main.js,引入上面的public-path.js,改写render,添加生命周期函数等,最终如下:

import './public-path' // 注意需要引入public-path
import Vue from 'vue'
import App from './App.vue'
import routes from './router'
import VueRouter from 'vue-router'
import store from './store'
// import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
import Element from 'element-ui'

Vue.config.productionTip = false

Vue.use(VueRouter)

Vue.use(Element, {
  size: 'medium' // set element-ui default size
})

let instance = null
/**
 * 渲染函数
 * 两种情况:主应用生命周期钩子中运行 / 微应用单独启动时运行
 */
function render (props = {}) {
  const { container, routerBase } = props
  // 在 render 中创建 VueRouter,可以保证在卸载微应用时,移除 location 事件监听,防止事件污染
  const router = new VueRouter({
    base: window.__POWERED_BY_QIANKUN__ ? routerBase : process.env.BASE_URL,
    mode: 'history',
    routes
  })
  instance = new Vue({
    router,
    store,
    render: h => h(App)
  }).$mount(container ? container.querySelector('#app') : '#app')
}
// 独立运行时,直接挂载应用
if (!window.__POWERED_BY_QIANKUN__) {
  render()
}
/**
 * bootstrap 只会在微应用初始化的时候调用一次,下次微应用重新进入时会直接调用 mount 钩子,不会再重复触发 bootstrap。
 * 通常我们可以在这里做一些全局变量的初始化,比如不会在 unmount 阶段被销毁的应用级别的缓存等。
 */
export async function bootstrap () {
  console.log('[vue] vue app bootstraped')
}
/**
 * 应用每次进入都会调用 mount 方法,通常我们在这里触发应用的渲染方法
 */
export async function mount (props) {
  console.log('[vue] props from main framework', props)

  render(props)
}

/**
 * 应用每次 切出/卸载 会调用的方法,通常在这里我们会卸载微应用的应用实例
 */
export async function unmount () {
  instance.$destroy()
  instance.$el.innerHTML = ''
  instance = null
}

至此,基础版本的vue子应用配置好了,同理再运行一个vue项目(sub-vue2)即可查看效果(暂时这里不展示其他技术栈的应用)

注意:以上的基座(主应用)和微应用路由都只能采用 history模式

如果微应用采用的hash路由模式,则主应用需修改子应用配置

const microApps = [
    {
      name: 'sub-vue1',
      entry: '//localhost:7777/',
      //activeRule: '/sub-vue1',
      activeRule: getActiveRule(`#/sub-vue1`),//修改子应用路由匹配规则
      container: '#subapp-viewport', // 子应用挂载的div
      props: {
        routerBase: '/sub-vue1' // 下发路由给子应用,子应用根据该值去定义qiankun环境下的路由
      }
    },
    {
      name: 'sub-vue2',
      entry: '//localhost:7788/',
      //activeRule: '/sub-vue2',
      activeRule: getActiveRule(`#/sub-vue2`),//修改子应用路由匹配规则
      container: '#subapp-viewport', // 子应用挂载的div
      props: {
        routerBase: '/sub-vue2'
      }
    }
  ]


const getActiveRule = (hash) => (location) => location.hash.startsWith(hash);

export default microApps

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值