关于ant desgin of vue 微前端qiankun项目集成
qiankun介绍
qiankun 是一个基于 single-spa 的微前端实现库,旨在帮助大家能更简单、无痛的构建一个生产可用微前端架构系统。
什么是微前端
微前端架构具备以下几个核心价值:
-
技术栈无关
主框架不限制接入应用的技术栈,子应用具备完全自主权
-
.独立开发、独立部署
子应用仓库独立,前后端可独立开发,部署完成后主框架自动完成同步更新
-
增量升级
在面对各种复杂场景时,我们通常很难对一个已经存在的系统做全量的技术栈升级或重构,而微前端是一种非常好的实施渐进式重构的手段和策略
-
独立运行时
每个子应用之间状态隔离,运行时状态不共享
步骤
- 下载qiankun
$ git clone https://github.com/umijs/qiankun.git
- 安装依赖
$ yarn install
$ yarn examples:install
- 运行qiankun项目
$ yarn examples:start
- 查看项目是否跑成功
http://localhost:7099
集成ant desgin of vue项目到qiankun
- 主项目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>
- 注册子应用(在主项目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);
},
],
},
);
- 子项目中新增一个便于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__;
}
- 子项目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
}
- 子项目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)
})
- 子项目中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: []
}