前言:
最近有一个项目在实现微前端,把几个独立的项目集成一个项目里,选择了qiankun技术栈。
qinakun 官网 使用指南
使用时遇到了 主应用(父),子应用之间需要传递消息。特此记录一下。
实现过程:
我找了一下,实现 通信的方式挺多的 props、第三方库 比如 vuex\redux等等、官方提供的 initGlobalState 、 本地存储(sessionStorage\localStorage)。其他通信方式可参考:
微前端:qiankun的五种通信方式
如果简单的通信可以用 本地存储实现这个 很快。
我选择了官方提供的 initGlobalStat API,原因是我需要接入 4个子系统,不能 每个都用第三方库。实际上 initGlobalState 也是借助了 props实现。
在主应用里 的入口文件 或者注册微应用 的文件里写上:
import {
initGlobalState } from 'qiankun';
let state={
message:"123"
}
// 初始化 state
const actions = initGlobalState(state);
actions.onGlobalStateChange((state, prev) => {
// state: 变更后的状态; prev 变更前的状态
console.log(state, prev);
});
actions.setGlobalState(state);
//actions.offGlobalStateChange();
需要注意的是 把 actions.offGlobalStateChange(); 这行注释掉。否则无法完成通信。
子应用里需要 从生命周期 mount 中获取通信方法 。这个生命周期需要写在 入口文件(一般是 app.js\main.js\index.js等等)。
因为我的子应用里 没有入口文件 所以 需要在src下新建一个 app.js。然后写上:
export const qiankun = {
// 应用加载之前
async bootstrap(props) {
console.log('子应用初始化1', props);
},
// 应用 render 之前触发
async mount(props) {
if(props){
//把 qiankun 的props 挂载到全局变量
window.qiankunProps=props;
}
},
// 应用卸载之后触发
async unmount(props) {
console.log('子应用已卸载1', props);
},
};
umi qiankun 子应用配置生命周期钩子
上面的写法是 umi框架的写法,因为我的项目基于umi所以用的是上面这种写法。
其他框架就可以按照官方文档写:
/**
* bootstrap 只会在微应用初始化的时候调用一次,下次微应用重新进入时会直接调用 mount 钩子,不会再重复触发 bootstrap。
* 通常我们可以在这里做一些全局变量的初始化,比如不会在 unmount 阶段被销毁的应用级别的缓存等。
*/
export async function bootstrap() {
console.log('react app bootstraped');
}
/**
* 应用每次进入都会调用 mount 方法,通常我们在这里触发应用的渲染方法
*/
export async function mount(props) {
if(props){
//把 qiankun 的props 挂载到全局变量
window.qiankunProps=props;
}
}
/**
* 应用每次 切出/卸载 会调用的方法,通常在这里我们会卸载微应用的应用实例
*/
export async function unmount(props) {
}
/**
* 可选生命周期钩子,仅使用 loadMicroApp 方式加载微应用时生效
*/
export async function update(props) {
console.log('update props', props);
}
qiankunProps需要全局使用,我选择挂载到window上,如果你是vue的话 可以直接挂载到 vue实例上。Vue.$qinakun=xxx。
然后 在其他页面就可以使用window?.qiankunProps?.setGlobalState发送消息 :
window?.qiankunProps?.setGlobalState({
message:"子应用发送的消息"
})
如果 你有入口文件,则可以直接在入口文件里写上 声明周期方法 ,不需要新建 文件了。不过 新建一个文件 在 入口文件引入 执行也可以(分模块 看起来更清晰)。
如何 验证是否 通信成功了?
只需要看控制台 主应用里 onGlobalStateChange 里打印的结果即可 默认会打印一下默认值。触发setGlobalState 后会再次打印,打印的值是传入的值,即通信成功。
遇到的问题:
本地 启动子应用可以,通信,生命周期都走了。但 子应用一打包 生命周期就不运行了。
需要 子应用 打包时的webpack配置一下:
webpack:
webpack v5:
const packageName = require('./package.json').name;
module.exports = {
output: {
library: `${
packageName}-[name]`,
libraryTarget: 'umd',
chunkLoadingGlobal: `webpackJsonp_${
packageName}`,
},
};
webpack v4:
const packageName = require('./package.json').name;
module.exports = {
output: {
library: `${
packageName}-[name]`,
libraryTarget: 'umd',
jsonpFunction: `webpackJsonp_${
packageName}`,
},
};
其他打包工具,官网没给,但原理差不多,需要自行查文档。
具体可参考:
配置微应用的打包工具
如果报:Application died in status LOADING_SOURCE_CODE: You need to export the functional lifecycles in xxx entry。
可以参考:
Application died in status LOADING_SOURCE_CODE: You need to export the functional lifecycles in xxx entry
建议遇到问题优先查看文档:
qiankun 官方文档
qiankun 官方文档 常见问题
我还遇到了,样式冲突,按照文档里 常见问题的解决方案就可以解决。 样式隔离,比如 我主应用用了antd,子应用也用了。就会有样式冲突。
如何确保主应用跟微应用之间的样式隔离