qiankun方案
优点
1.与技术栈无关,子应用独立开发、独立部署
使用
本文档以vue
项目为示例,主应用采用history
路由模式,子应用一个为hash
模式,一个为history
模式
qainkun
规定:如果主应用是history
模式,则子应用可以是hash
或history
模式;如果主应用是hash
模式,则子应用必须为hash
模式。详情见官方文档(微应用的路由模式如何选择)
主应用配置
1.安装qiankun
npm i qiankun -S
2.在主应用入口文件中注册微应用
import { registerMicroApps, start } from 'qiankun';
// 注册子应用列表
registerMicroApps([
{
name: 'vue2App1', // 子应用名称
entry: process.env.VUE_APP_APP1, // 子应用入口地址,默认会加载该地址下的html文件,可利用环境变量区分不同环境的入口地址
container: '#subapp-container', // 加载的容器
activeRule: '/vue2App1' // 匹配的路由规则,访问以‘/vue2App1’开头的URL时会走这里
},
{
name: 'vue2App2',
entry: process.env.VUE_APP_APP2,
container: '#subapp-container',
activeRule: '/vue2App2',
},
]);
// 启动微服务
start();
3. 在路由文件中增加指向子应用的路由
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
const routes = [
{
path: '/',
redirect: '/main'
},
{
path: '*',
name: '404',
component: () => import('@/views/404')
},
{
path: '/login',
name: 'Login',
component: () => import('@/views/Login')
},
{
path: '/main',
name: 'Main',
component: () => import('@/views/Main'),
redirect: '/main/home',
children: [
{
path: 'home',
name: 'Home',
component: () => import('@/views/Home')
}
]
},
{
// 以‘/vue2App1/‘开头的url会匹配到该路由
// 子应用列表中的activeRule属性匹配这里的路由
path: '/vue2App1/*',
component: () => import('@/views/Main')
},
{
// 以‘/vue2App2/‘开头的url会匹配到该路由
// 子应用列表中的activeRule属性匹配这里的路由
path: '/vue2App2/*',
component: () => import('@/views/Main')
}
]
const router = new VueRouter({
mode: 'history',
routes,
})
export default router
4.指定子应用加载容器
<template>
<div class="main">
<header>
<div class="header-content">
<span>这是主应用的main页面</span>
</div>
<div style="margin-top: 16px; line-height:22px">
<!-- 指向子应用中‘/’匹配到的路由 -->
<router-link to="/vue2App1/">vue2App1</router-link>
<!-- 指向子应用中‘/app1/login’匹配到的路由 -->
<router-link to="/vue2App1/app1/login">vue2App1</router-link>
<!-- 指向hash模式的子应用中‘/main/demo1’匹配到的路由 -->
<router-link to="/vue2App2/#/main/demo1">vue2App2</router-link>
</div>
</header>
<div class="main-content">
<!-- 主应用渲染容器 -->
<router-view/>
<!-- 子应用渲染容器 -->
<!-- 与子应用注册列表中的container属性一致 -->
<div id="subapp-container"></div>
</div>
</div>
</template>
微应用配置
vue2
项目
1.在 src
目录新增 public-path.js
:
if (window.__POWERED_BY_QIANKUN__) {
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
2.入口文件 main.js
修改,引入public-path.js
,区分应用挂载的容器(独立运行还是乾坤环境运行)
// 需要引入public-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;
let router = null;
let instance = null;
function render(props = {}) {
const { container } = props;
router = new VueRouter({
// base默认为/, 在乾坤环境手动设置为主应用中activeRule值
// 如果子应用为hash模式则无需配置base
base: window.__POWERED_BY_QIANKUN__ ? '/vue2App1' : '/',
mode: 'history',
routes,
});
instance = new Vue({
router,
store,
render: (h) => h(App),
}).$mount(container ? container.querySelector('#app') : '#app');
}
// 独立运行时,__POWERED_BY_QIANKUN__变量存在则为qiankun环境运行
if (!window.__POWERED_BY_QIANKUN__) {
render();
}
// 子应用初始化时调用一次
export async function bootstrap() {
console.log('[bootstrap');
}
// 每次进入应用都会调用
export async function mount(props) {
console.log('mount', props);
render(props);
}
// 每次卸载应用都会调用
export async function unmount() {
instance.$destroy();
instance.$el.innerHTML = '';
instance = null;
router = null;
}
3.打包配置修改(vue.config.js
)
const { name } = require('./package');
module.exports = {
devServer: {
headers: {
'Access-Control-Allow-Origin': '*', // 允许跨域
},
},
configureWebpack: {
output: {
library: `${name}-[name]`,
libraryTarget: 'umd', // 把微应用打包成 umd 库格式
jsonpFunction: `webpackJsonp_${name}`, // webpack 5 需要把 jsonpFunction 替换成 chunkLoadingGlobal
},
},
};
iframe方案
<!-- html框架标签 在页面中画一个区域来展示src里的页面 -->
<iframe src="https://qiankun.umijs.org/zh" width="800px" height="500px"></iframe>
// 获取iframe内的document和window
let iframe = document.querySeletor("iframe")
iframeDoc = iframe.contentWidow.document
iframeWin = iframe.contentWindow
优点
1.使用简单,每个iframe
内的内容完全隔离、互不影响,适合嵌套简单页面
缺点
1.url
不同步。刷新浏览器,iframe
中的路由会丢失
2.ui
不同步,DOM
结构不共享
3.全局上下文完全隔离,内存变量不共享
4.慢。每次子应用进入都是一次浏览器上下文重建、资源重新加载的过程。