qiankun:点击这里
解决问题:将多个系统或者不同技术框架项目可以整合到一起,以前使用iframe方案
这里的使用的是国内目前比较成熟的qiankun
准备工作: 3个应用
基座:主应用(main-app),使用vue-cli3配合vue2搭建
子应用1:vue-app,使用vue-cli3配合vue2搭建
子应用2:react-app,使用cra
子应用路由模式是history
1、将基座搭建好之后,开始引入qiankun,注册微应用,
这里我将微应用加载在某一个页面中,所以不在main.j始终调用start函数
新建一个qiankun.config.js配置注册的微应用
const state = { user: 'tom' } // 用来传递给子应用
export default [{
name: 'reactApp',
entry: '//localhost:3000',
container: '#container',
activeRule: '/portal/react-app'
},
{
name: 'vueApp',
entry: '//localhost:7200',
container: '#container',
activeRule: '/portal/vue-app',
props: state, // 使用props传递参数
}]
main.js中引入qiankun.config.js并且注册
import { registerMicroApps, initGlobalState } from 'qiankun'
import APPS from '../config/qiankun.config.js'
registerMicroApps(APPS, {
beforeLoad: (app) => console.log('before load', app.name), // 生命周期
beforeMount: [
app => {
console.log('[LifeCycle] before mount %c%s', 'color: green;', app.name);
},
]
});
在/src/views中新建Index.vue,我们要在这里加载微应用
<template>
<!-- 微应用容器 -->
<div id='container'></div>
</template>
<script>
import { start } from 'qiankun'
export default {
// 在mounted周期调用 start 函数
mounted () {
if (!window.qiankunStarted) { // 避免重复调用
window.qiankunStarted = true;
start(true);
}
}
}
</script>
主应用路由表中也要注意修改,因为我们是在某一页面加载微应用,所以路径后面要加*,这样为了匹配注册子应用时候路径的activeRule字段
{
path: '/portal/*',
name: 'portal',
component: SUB_HOME
}
注意: 这里的路径需要和子应用中的对应,下面会讲到
以上主应用就搭建好了,这里有一个小插曲,其实一开始主应用是使用vue-cli3+vue3+vue-router4搭建的,但是vue-router4好像不支持通配符的使用,所以将主应用改成vue2的,之后会研究一下为什么支持
2、子应用----vue-app
子应用使用vue-cli3创建项目,创建好之后,需要修改main.js和router.js两个文件
在src下面创建一个public-path.js
if (window.__POWERED_BY_QIANKUN__) {
// eslint-disable-next-line no-undef
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
修改router.js,只将路由表导出,将路由表的注册移动到main.js中
import Home from '../views/Home.vue'
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
}
]
export default routes
创建vue.config.js,进行一些配置
注意事项
修改端口,和主应用中注册时候的一致,设置header头允许跨域
const { name } = require('./package');
module.exports = {
publicPath: '//localhost:7200/',
devServer: {
port: 7200,
headers: {
'Access-Control-Allow-Origin': '*',
},
},
configureWebpack: {
output: {
library: `${name}-[name]`,
libraryTarget: 'umd', // 把微应用打包成 umd 库格式
jsonpFunction: `webpackJsonp_${name}`,
}
}
}
main.js中需要将poublic-path.js在顶部引入
import './public-path'
import Vue from 'vue'
import VueRouter from 'vue-router'
import App from './App.vue'
import routes from './router'
import store from './store'
Vue.config.productionTip = false
Vue.use(VueRouter)
let router = null;
let instance = null;
function render(props = {}) {
const { container } = props;
// 这里的base在以微应用加载时候的路径一定和主应用中的activeRules匹配
router = new VueRouter({
base: window.__POWERED_BY_QIANKUN__ ? '/portal/vue-app' : '/',
mode: 'history',
routes,
});
instance = new Vue({
router,
store,
render: (h) => h(App),
}).$mount(container ? container.querySelector('#app') : '#app');
}
// 独立运行时
if (!window.__POWERED_BY_QIANKUN__) {
render();
}
export async function bootstrap() {
// console.log('[vue] vue app bootstraped');
}
export async function mount(props) {
props.onGlobalStateChange((next, prev) => {
console.log(next, prev);
})
render(props);
}
export async function unmount() {
instance.$destroy();
instance.$el.innerHTML = '';
instance = null;
router = null;
}
目前为止:vue-app子应用已经成功加载
3、开始react-app子应用
react是使用create-react-app脚手架创建的
在src目录中创建public-path.js
if (window.__POWERED_BY_QIANKUN__) {
// eslint-disable-next-line no-undef
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
安装react-router-dom
修改index.js
import './public-path';
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import { BrowserRouter } from 'react-router-dom'
function render(props) {
const { container } = props;
ReactDOM.render(<BrowserRouter basename={window.__POWERED_BY_QIANKUN__ ? '/portal/react-app' : '/'}><App /></BrowserRouter>, container ? container.querySelector('#root') : document.querySelector('#root'));
}
if (!window.__POWERED_BY_QIANKUN__) {
render({});
}
export async function bootstrap() {
// console.log('[react16] react app bootstraped');
}
export async function mount(props) {
console.log('===========');
render(props);
}
export async function unmount(props) {
const { container } = props;
ReactDOM.unmountComponentAtNode(container ? container.querySelector('#root') : document.querySelector('#root'));
}
最后的成果:
之后要处理的问题:cookie共享,子应用之间跳转,子应用之间数据可否共享
生命周期
部署到服务有什么坑,之后会进一步实践
未解决的问题:
vue-app子应用在本地刷新之后报404