一、主应用
1、引用乾坤
// package.json
"qiankun": "^2.6.3",
2、主节点不能和子应用相同
子应用的节点基本叫做app,主应用就不能叫做app,否则会出错
<div
id="frontendApp"
>
<!-- <router-view
注意其他使用到的地方和样式都要跟着改过来
#frontendApp{
<body>
<div id="frontendApp"></div>
</body>
</html>
new Vue({
el: '#frontendApp',
router,
store,
render: h => h(App)
3、子应用配置
function genActiveRule(routerPrefix) {
return location => location.pathname.startsWith(routerPrefix);
}
let config;
switch (process.env.NODE_ENV) {
case 'development':
config = {
apps: [
{
name: 'frontMicroApp', // 应用的名字
entry: 'https://a.b.com',
container: '#microAppContainer', // 容器名(此项目页面中定义的容器id,用于把对应的子应用放到此容器中)
activeRule: genActiveRule('/frontMicroAppPath'), // 激活的路径
},
],
};
break;
}
export default config;
4、添加容器
<div id="microAppContainer"></div>
5、乾坤开启
import { registerMicroApps, start } from 'qiankun';
import qiankunConfig from 'common/qiankun.js';
// ......
let app = null;
function render() {
if (!app) {
// eslint-disable-next-line no-new
app = new Vue({
el: '#frontendApp',
router,
store,
render: h => h(App)
});
}
}
function initApp() {
render();
}
initApp();
registerMicroApps(qiankunConfig.apps); // 注册应用
start({
prefetch: false // 取消预加载
});// 开启
6、子应用事件通讯
import { initGlobalState } from 'qiankun';
//......
const actions = initGlobalState({ logout: false });
actions.onGlobalStateChange((state, prev) => {
if (state.logout === true) {
logOutHandler();
}
});
function logOutHandler() {
// do logout ...
}
7、去掉冲突数据
1、去掉window.Vue
// window.Vue = Vue;
8、接口代理
'/frontMicroAppApi': {
target: 'http://a.b.com',
changeOrigin: true, // 是否跨域
pathRewrite: {
'^/frontMicroAppApi': '/api',
}
},
二、子应用
1、打包设置
webpack打包设置:(1)libraryTarget为umd;(2)library为和主应用商量好的名字;
output: {
library: 'frontMicroApp',
libraryTarget: 'umd',
2、打包资源放到指定文件夹
正常打包资源放在static文件夹,这样多个应用资源路径就相同冲突了,每个应该根据项目定义文件名,不要定义为static。
outputDir: 'dist/appOneStatic',
同时记得清除项目中使用到static路径的地方,都要改动过来。
项目里public文件夹会直接拷贝到打包目录下,同样里面的资源文件夹也要更改,不要定义为static等;
3、开发环境允许跨域访问
devServer设置允许访问和允许跨域访问:(1)headers设置Access-Control-Allow-Origin;(2)disableHostCheck设置为true;
headers: {
// 因为qiankun内部请求都是fetch来请求资源,所以子应用必须允许跨域
'Access-Control-Allow-Origin': '*'
},
disableHostCheck: true, // 为了把本地 localhost 映射到外网
4、接口请求加上统一前缀
子应用的请求都在主应用发起,所以所有子应用请求都要加上一个和主应用协商好的前缀。
主应用设置反向代理把这个前缀的请求转发到子应用。
建议在一个公共的地方设置,避免漏掉有的请求没有设置。也方便修改、管理等。
if (window.__POWERED_BY_QIANKUN__) {
const qianKunPrefix = '/frontMicroAppApi'; // 和主应用的代理保持一致
api = qianKunPrefix + api;
}
5、注册乾坤子应用
5.1、修改main.js,初始化路由和应用实例
let router = null;
let instance = null;
function render(props) {
// 初始化路由
router = new Router({
mode: 'history',
base: '/frontMicroAppPath',
routes: routes,
scrollBehavior(to, from, savedPosition) {
return { x: 0, y: 0 };
},
linkActiveClass: 'active',
});
// 初始化应用
instance = new Vue({
el: '#app',
router,
store,
components: { App },
template: '<App/>'
});
}
5.2、非乾坤时,独立运行
if (!window.__POWERED_BY_QIANKUN__) { // 默认独立运行
render();
}
5.3、动态添加publicPath
if (window.__POWERED_BY_QIANKUN__) { // 动态添加publicPath
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__; /* eslint-disable-line */
}
5.4、子应用必须暴露三个接口:bootstrap、mount、unmount
export async function bootstrap(props) {
};
export async function mount(props) {
render(props);
}
export async function unmount(props) {
instance.$destroy();
instance.$el.innerHTML = '';
instance = null;
router = null;
}
6、路由设置
6.1、base设置
添加一个base,和主应用协商好base路径,主应用根据base路径加载子应用。
if (window.__POWERED_BY_QIANKUN__) {
new Router({
base: '/frontMicroAppPath',
....
}
6.2、去掉*路径
避免子应用路径去影响到主应用的路径跳转,所以子应用的*路径配置要去掉。
代码逻辑里,默认先不添加,判断非乾坤环境再加上。
if (!window.__POWERED_BY_QIANKUN__) {
routes.push({
path: '*',
redirect: '/home'
})
}
6.3、实例化路由
在main.js的乾坤的render方法实例化路由
import routes from './router';
let router = null;
function render(props) {
router = new Router({
mode: 'history',
base: '/frontMicroAppPath',
routes: routes,
scrollBehavior(to, from, savedPosition) {
return { x: 0, y: 0 };
},
linkActiveClass: 'active',
});
......
}
6.4、清空路由
在main.js的乾坤的unmount方法情况路由
export async function unmount(props) {
......
router = null;
}
7、事件通讯
7.1、在main.js的mount方法中获得乾坤的全局状态
let qianKunProps = '';
export async function mount(props) {
qianKunProps = props;
render(props);
}
7.2、乾坤全局状态提供的事件通讯方法
onGlobalStateChange: (callback: OnGlobalStateChangeCallback, fireImmediately?: boolean) => void, 在当前应用监听全局状态,有变更触发 callback,fireImmediately = true 立即触发 callback
setGlobalState: (state: Record<string, any>) => boolean, 按一级属性设置全局状态,微应用中只能修改已存在的一级属性
offGlobalStateChange: () => boolean,移除当前应用的状态监听,微应用 umount 时会默认调用
7.3、登出通讯例子
这个事件通讯的原理类似于响应式,一个地方改变会通知到别的地方。
所以子应用和主应用了解清楚定义了哪些值用于监听事件。
例如主应用设置了监听logout值去调用登出方法:
import { initGlobalState } from 'qiankun';
const actions = initGlobalState({ logout: false });
actions.onGlobalStateChange((state, prev) => {
if (state.logout === true) {
logOutHandler();
}
});
那么,子应用只需要改动logout的值,就能触发主应用的登出操作:
export function qianKunLogout() {
if (window.__POWERED_BY_QIANKUN__ && qianKunProps && qianKunProps.setGlobalState) {
qianKunProps.setGlobalState({
logout: true,
});
}
}
import { qianKunLogout } from '@/main.js';
if (window.__POWERED_BY_QIANKUN__) {
qianKunLogout();
return;
}
8、注意点
8.1、主应用设置的name和子应用打包的library要对上
{
name: 'frontMicroApp', // 应用的名字
entry: '...', //
container: '...',
activeRule: genActiveRule('/...'),
},
output: {
library: 'frontMicroApp', // 和主应用的name对应上
libraryTarget: 'umd',
}
8.2、主应用的activeRule要和子应用路由的base对应上
{
name: '...', // 应用的名字
entry: '...', //
container: '...',
activeRule: genActiveRule('/frontMicroAppPath'),
},