微前端qiankun集成

关于ant desgin of vue 微前端qiankun项目集成javascript

qiankun介绍

qiankun 是一个基于 single-spa 的微前端实现库,旨在帮助你们能更简单、无痛的构建一个生产可用微前端架构系统。css

什么是微前端

微前端架构具有如下几个核心价值:html

  • 技术栈无关
    主框架不限制接入应用的技术栈,子应用具有彻底自主权
  • .独立开发、独立部署
    子应用仓库独立,先后端可独立开发,部署完成后主框架自动完成同步更新
  • 增量升级
    在面对各类复杂场景时,咱们一般很难对一个已经存在的系统作全量的技术栈升级或重构,而微前端是一种很是好的实施渐进式重构的手段和策略
  • 独立运行时
    每一个子应用之间状态隔离,运行时状态不共享

步骤

  1. 下载qiankun
$ git clone https://github.com/umijs/qiankun.git
  1. 安装依赖
$ yarn install
$ yarn examples:install
  1. 运行qiankun项目
$ yarn examples:start
  1. 查看项目是否跑成功
http://localhost:7099

集成ant desgin of vue项目到qiankun

  1. 主项目main中的index.html中修改侧边栏
<ul class="mainapp-sidemenu">
    <li onclick="push('/react16')">React16</li>
    <li onclick="push('/react15')">React15</li>
    <li onclick="push('/vue')">Vue</li>
    <li onclick="push('/angular9')">Angular9</li>
    <li onclick="push('/project')">蚂蚁</li>
 </ul>
  1. 注册子应用(在主项目main中的index.js中)
registerMicroApps(
  [
    {
      name: 'react16',
      entry: '//localhost:7100',
      render,
      activeRule: genActiveRule('/react16'),
    },
    {
      name: 'react15',
      entry: '//localhost:7102',
      render,
      activeRule: genActiveRule('/react15'),
    },
    {
      name: 'vue',
      entry: '//localhost:7101',
      render,
      activeRule: genActiveRule('/vue'),
    },
    {
      name: 'angular9',
      entry: '//localhost:7103',
      render,
      activeRule: genActiveRule('/angular9'),
    },
    {
      name: 'project',
      entry: '//localhost:8000',
      render,
      activeRule: genActiveRule('/project'),
    },
  ],
  {
    beforeLoad: [
      app => {
        console.log('[LifeCycle] before load %c%s', 'color: green;', app.name);
      },
    ],
    beforeMount: [
      app => {
        console.log('[LifeCycle] before mount %c%s', 'color: green;', app.name);
      },
    ],
    afterUnmount: [
      app => {
        console.log('[LifeCycle] after unmount %c%s', 'color: green;', app.name);
      },
    ],
  },
);
  1. 子项目中新增一个便于qiankun监听url变幻响应不一样子项目的js文件,与app.vue文件同级别新增public-path.js文件
if (window.__POWERED_BY_QIANKUN__) {
  // eslint-disable-next-line no-undef
  __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
  1. 子项目main.js文件改造,暴露子项目的三个周期bootstrap(),mount(props),unmount()
// ie polyfill
import './public-path'
import '@babel/polyfill'

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store/'
import { VueAxios } from './utils/request'

// mock
import './mock'

import bootstraps from './core/bootstrap'
import './core/use'

// 去掉权限
import './permission' // permission control

import './utils/filter' // global filter

Vue.config.productionTip = false

// mount axios Vue.$http and this.$http
Vue.use(VueAxios)
let instance = null
function render () {
  // router = new VueRouter({
  // base: window.__POWERED_BY_QIANKUN__ ? '/project' : '/',
  // mode: 'history',
  // routes
  // })

  instance = new Vue({
    router,
    store,
    created () {
      bootstraps()
    },
    render: h => h(App)
  }).$mount('#app')
}
// new Vue({
// router,
// store,
// created () {
// bootstrap()
// },
// render: h => h(App)
// }).$mount('#app')
if (!window.__POWERED_BY_QIANKUN__) {
  render()
}

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

export async function mount (props) {
  console.log('[vue] props from main framework', props)
  render()
}

export async function unmount () {
  instance.$destroy()
  instance = null
  // router = null
}
  1. 子项目router改造(router文件夹中的index.js中)
export default new Router({
  // mode: 'history',
  base: window.__POWERED_BY_QIANKUN__ ? '/project' : '/',
  mode: 'history',
  scrollBehavior: () => ({
    y: 0
  }),
  routes: constantRouterMap.concat(asyncRouterMap)
})
  1. 子项目中vue.config.js改造,注意此时的端口号得与以前主项目中的端口号一致
const path = require('path')
const webpack = require('webpack')
const packageName = require('./package.json').name

function resolve (dir) {
  return path.join(__dirname, dir)
}

// vue.config.js
module.exports = {
  /* Vue-cli3: Crashed when using Webpack `import()` #2463 https://github.com/vuejs/vue-cli/issues/2463 */
  /* pages: { index: { entry: 'src/main.js', chunks: ['chunk-vendors', 'chunk-common', 'index'] } }, */
  outputDir: 'dist',
  assetsDir: 'static',
  filenameHashing: true,
  configureWebpack: {
    output: {
      library: `${packageName}-[name]`,
      libraryTarget: 'umd',
      jsonpFunction: `webpackJsonp_${packageName}`
    },
    plugins: [
      // Ignore all locale files of moment.js
      new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/)
    ]
  },

  chainWebpack: config => {
    config.resolve.alias
      .set('@$', resolve('src'))
      .set('@api', resolve('src/api'))
      .set('@assets', resolve('src/assets'))
      .set('@comp', resolve('src/components'))
      .set('@views', resolve('src/views'))
      .set('@layout', resolve('src/layout'))
      .set('@static', resolve('src/static'))

    const svgRule = config.module.rule('svg')
    svgRule.uses.clear()
    svgRule
      .oneOf('inline')
      .resourceQuery(/inline/)
      .use('vue-svg-icon-loader')
      .loader('vue-svg-icon-loader')
      .end()
      .end()
      .oneOf('external')
      .use('file-loader')
      .loader('file-loader')
      .options({
        name: 'assets/[name].[hash:8].[ext]'
      })
    /* svgRule.oneOf('inline') .resourceQuery(/inline/) .use('vue-svg-loader') .loader('vue-svg-loader') .end() .end() .oneOf('external') .use('file-loader') .loader('file-loader') .options({ name: 'assets/[name].[hash:8].[ext]' }) */
  },

  css: {
    loaderOptions: {
      less: {
        modifyVars: {
          /* less 变量覆盖,用于自定义 ant design 主题 */
          /* 'primary-color': '#F5222D', 'link-color': '#F5222D', 'border-radius-base': '4px', */
        },
        javascriptEnabled: true
      }
    }
  },

  devServer: {
    // development server port 8000
    hot: true,
    disableHostCheck: true,
    overlay: {
      warnings: false,
      errors: true
    },
    headers: {
      'Access-Control-Allow-Origin': '*'
    },
    port: 8000
    // proxy: {
    // '/api': {
    // // target: 'https://mock.ihx.me/mock/5baf3052f7da7e07e04a5116/antd-pro',
    // target: 'https://mock.ihx.me/mock/5baf3052f7da7e07e04a5116/antd-pro',
    // ws: false,
    // changeOrigin: true
    // }
    // }
  },

  lintOnSave: undefined,
  // babel-loader no-ignore node_modules/*
  transpileDependencies: []
}