诺言开票软件
75.81MB · 2025-11-10
参考链接: [微前端][vue3 + vite + qiankun] 使用详解
一般来说,各个子应用是通过业务来划分的,不同业务线应该降低耦合度,尽量去避免通信,但是如果涉及到一些公共的状态或者操作,qiankun也是支持的。
qinkun提供了一个全局的GlobalState来共享数据,基座初始化之后,子应用可以监听到这个数据的变化,也能提交这个数据。
假设有如下一个具体的业务场景:有一个基座应用(主应用)和多个子应用(微前端应用)。我们假设有一个全局的用户信息状态(例如用户ID、用户名、权限等)需要在基座和所有子应用之间共享。当用户在基座应用中登录后,用户信息需要传递给所有子应用,同时子应用可能在某些操作后更新用户信息(例如更新用户昵称),并且其他子应用和基座需要响应这个更新。
多个子应用需要共享用户登录状态、用户信息和权限数据,避免重复登录和权限校验。
// 主应用 - 初始化全局状态
import { initGlobalState } from 'qiankun';
// 初始化状态
const initialState = {
user: {
id: null,
name: '',
avatar: '',
roles: [],
permissions: []
},
token: '',
isLoggedIn: false
};
const actions = initGlobalState(initialState);
// 用户登录后更新状态
actions.setGlobalState({
user: {
id: 12345,
name: '张三',
avatar: '/avatars/zhangsan.jpg',
roles: ['admin', 'user'],
permissions: ['read', 'write', 'delete']
},
token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
isLoggedIn: true
});
// 监听登录状态变化
actions.onGlobalStateChange((state, prevState) => {
// 主应用自身的状态同步
if (state.isLoggedIn !== prevState.isLoggedIn) {
console.log('登录状态变化:', state.isLoggedIn);
updateMainAppUI(state);
}
});
let globalAction = null;
// 子应用A - 用户管理
export async function mount(props) {
// 保存全局状态操作对象
globalAction = props;
// 监听全局状态变化
props.onGlobalStateChange((state, prevState) => {
// 用户信息变化时更新界面
if (state.user.id !== prevState.user.id) {
updateUserProfile(state.user);
}
// 权限变化时重新检查
if (state.user.permissions !== prevState.user.permissions) {
checkPermissions(state.user.permissions);
}
}, true); // 立即执行一次
// 渲染子应用
renderApp(props);
}
// 更新用户信息
const updateUserInfo = (newUserInfo) => {
globalAction.setGlobalState({
user: {
...globalAction.getGlobalState().user,
...newUserInfo
}
});
};
// 检查权限
const checkPermissions = (requiredPermission) => {
const { permissions } = globalAction.getGlobalState().user;
return permissions.includes(requiredPermission);
};
qiankun 的 initGlobalState 方法提供了一种在微前端架构中主应用与子应用之间通信的机制。其原理主要基于以下步骤:
状态初始化:主应用调用 initGlobalState 初始化全局状态,并返回一个对象,该对象包含设置状态、监听状态变化等方法。
状态存储:全局状态被存储在一个中心化的地方,并且可以被多个子应用访问。
状态更新:当主应用或子应用调用 setGlobalState 更新状态时,会触发所有已经注册的监听器(包括主应用和子应用)。
状态监听:子应用(或主应用)可以通过 onGlobalStateChange 注册监听函数,当全局状态发生变化时,会执行这些监听函数。
状态隔离:qiankun 会确保每个子应用都能独立地监听全局状态,并且不会互相干扰。
下面是一个简化的实现原理示例,帮助理解 qiankun 的全局状态管理:
// 模拟 qiankun 的全局状态管理
let globalState = {}; // 全局状态
let listeners = []; // 监听器列表
function initGlobalState(initialState = {}) {
// 合并初始状态
globalState = { ...globalState, ...initialState };
// 返回一个对象,包含操作全局状态的方法
return {
// 设置全局状态
setGlobalState(state) {
const prevState = { ...globalState };
globalState = { ...globalState, ...state };
// 通知所有监听器
listeners.forEach(listener => {
listener(globalState, prevState);
});
},
// 监听全局状态变化
onGlobalStateChange(listener, immediate = false) {
listeners.push(listener);
// 如果立即执行,则立即调用一次监听器
if (immediate) {
listener(globalState, globalState);
}
// 返回一个取消监听的函数
return () => {
const index = listeners.indexOf(listener);
if (index > -1) {
listeners.splice(index, 1);
}
};
},
// 获取当前全局状态
getGlobalState() {
return globalState;
},
// 移除所有监听器(通常用于应用卸载时)
offGlobalStateChange() {
listeners = [];
}
};
}
// 主应用使用
const actions = initGlobalState({ user: 'main' });
// 子应用使用
// 假设子应用通过某种方式获取到 actions(通常是通过 props 传递)
// 子应用监听状态变化
const unsubscribe = actions.onGlobalStateChange((state, prevState) => {
console.log('子应用监听到状态变化', state, prevState);
}, true);
// 子应用更新状态
actions.setGlobalState({ user: 'subapp' });
// 取消监听
// unsubscribe();
在实际的 qiankun 实现中,还会考虑以下方面:
状态隔离:确保子应用在卸载时自动取消监听,避免内存泄漏。
状态同步:当子应用初始化时,能够获取到最新的全局状态。
多实例支持:在多个子应用同时运行时,每个子应用都可以独立地监听和更新状态。
在 qiankun 的源码中,全局状态的管理是在 src/globalState.ts 中实现的。它使用了类似发布-订阅的模式,并且通过一个全局的变量来存储状态。主应用和子应用通过这个全局的变量进行通信。
注意:在子应用中,qiankun 会通过生命周期函数的参数将全局状态的操作方法传递给子应用,子应用在挂载时可以通过 props 获取到这些方法。
例如,在主应用中注册子应用时:
import { registerMicroApps, start } from 'qiankun';
registerMicroApps([
{
name: 'subapp',
entry: '//localhost:7100',
container: '#subapp-container',
activeRule: '/subapp',
props: {
// 传递全局状态操作方法
onGlobalStateChange: actions.onGlobalStateChange,
setGlobalState: actions.setGlobalState,
getGlobalState: actions.getGlobalState,
},
},
]);
start();
在子应用中,在生命周期函数中接收:
export async function mount(props) {
// 子应用可以使用 props 上的方法
props.onGlobalStateChange((state, prev) => {
// 状态变化时的操作
});
props.setGlobalState({ ... });
}
这样,主应用和子应用就可以通过这个全局状态进行通信了。
Qiankun 的全局状态管理基于发布-订阅模式,采用中心化的状态存储和事件通知机制。
// 简化的核心实现原理
class GlobalStateManager {
constructor() {
this.state = {}; // 全局状态存储
this.listeners = new Map(); // 监听器映射表
this.subAppStates = new Map(); // 子应用状态快照
this.isMainApp = true; // 标识是否为主应用
}
// 初始化全局状态
initGlobalState(initialState = {}) {
this.state = { ...initialState };
return this.createActions();
}
// 创建状态操作方法
createActions() {
return {
setGlobalState: (state) => this.setGlobalState(state),
onGlobalStateChange: (callback, immediately = false) =>
this.onGlobalStateChange(callback, immediately),
offGlobalStateChange: (callback) => this.offGlobalStateChange(callback),
getGlobalState: () => this.getGlobalState()
};
}
// 设置全局状态
setGlobalState(state) {
const prevState = { ...this.state };
// 合并新状态
this.state = {
...this.state,
...state
};
// 通知所有监听器
this.notifyListeners(this.state, prevState);
return true;
}
// 注册状态变化监听器
onGlobalStateChange(callback, immediately = false) {
const listenerId = Symbol('listener');
this.listeners.set(listenerId, callback);
// 立即执行一次
if (immediately) {
try {
callback(this.state, this.state);
} catch (error) {
console.error('Global state listener error:', error);
}
}
// 返回取消监听函数
return () => {
this.listeners.delete(listenerId);
};
}
// 移除监听器
offGlobalStateChange(callback) {
for (const [id, listener] of this.listeners.entries()) {
if (listener === callback) {
this.listeners.delete(id);
break;
}
}
}
// 获取当前状态
getGlobalState() {
return { ...this.state };
}
// 通知所有监听器
notifyListeners(currentState, previousState) {
this.listeners.forEach((listener, id) => {
try {
// 使用 setTimeout 确保异步执行,避免阻塞
setTimeout(() => {
if (this.listeners.has(id)) {
listener(currentState, previousState);
}
}, 0);
} catch (error) {
console.error(`Listener ${id.toString()} error:`, error);
}
});
}
// 子应用挂载时的状态同步
syncStateToSubApp(subAppName, actions) {
// 保存子应用的状态操作引用
this.subAppStates.set(subAppName, actions);
// 返回子应用专用的状态操作对象
return this.createSubAppActions(actions);
}
// 创建子应用专用的操作对象
createSubAppActions(subAppActions) {
return {
...subAppActions,
// 可以在这里添加子应用特定的逻辑
getSubAppState: () => this.getGlobalState()
};
}
}
下面是更接近 Qiankun 实际实现的完整代码:
// globalState.js - Qiankun 全局状态管理核心实现
class GlobalState {
constructor() {
// 全局状态存储
this.state = {};
// 监听器存储:Map<symbol, Function>
this.listeners = new Map();
// 标识是否已初始化
this.initialized = false;
// 主应用标识
this.isMaster = typeof window !== 'undefined' &&
window.__POWERED_BY_QIANKUN__ !== true;
}
/**
* 初始化全局状态
* @param {Object} initialState 初始状态
* @returns {Object} 状态操作对象
*/
initGlobalState(initialState = {}) {
if (this.initialized) {
console.warn('[qiankun] Global state already initialized');
return this.getActions();
}
this.state = this.deepClone(initialState);
this.initialized = true;
// 在开发模式下打印日志
if (process.env.NODE_ENV === 'development') {
console.log('[qiankun] Global state initialized:', this.state);
}
return this.getActions();
}
/**
* 获取状态操作对象
*/
getActions() {
return {
setGlobalState: this.setGlobalState.bind(this),
onGlobalStateChange: this.onGlobalStateChange.bind(this),
offGlobalStateChange: this.offGlobalStateChange.bind(this),
getGlobalState: this.getGlobalState.bind(this),
};
}
/**
* 设置全局状态
* @param {Object} state 新状态
* @param {boolean} overwrite 是否覆盖整个状态
*/
setGlobalState(state, overwrite = false) {
if (!this.initialized) {
console.error('[qiankun] Global state not initialized');
return false;
}
const prevState = this.deepClone(this.state);
if (overwrite) {
this.state = this.deepClone(state);
} else {
this.state = this.mergeState(this.state, state);
}
// 触发监听器
this.emit(prevState);
if (process.env.NODE_ENV === 'development') {
console.log('[qiankun] Global state updated:', {
from: prevState,
to: this.state
});
}
return true;
}
/**
* 注册状态变化监听器
* @param {Function} listener 监听函数
* @param {boolean} fireImmediately 是否立即执行
*/
onGlobalStateChange(listener, fireImmediately = false) {
if (typeof listener !== 'function') {
throw new Error('[qiankun] Listener must be a function');
}
const listenerId = Symbol('qiankun-global-state-listener');
this.listeners.set(listenerId, listener);
// 立即执行一次
if (fireImmediately) {
try {
setTimeout(() => {
if (this.listeners.has(listenerId)) {
listener(this.state, this.state);
}
}, 0);
} catch (error) {
console.error('[qiankun] Fire immediately error:', error);
}
}
// 返回取消监听函数
return () => {
this.listeners.delete(listenerId);
};
}
/**
* 移除状态变化监听器
* @param {Function} listener 要移除的监听函数
*/
offGlobalStateChange(listener) {
for (const [id, fn] of this.listeners.entries()) {
if (fn === listener) {
this.listeners.delete(id);
break;
}
}
}
/**
* 获取当前全局状态
*/
getGlobalState() {
return this.deepClone(this.state);
}
/**
* 触发所有监听器
* @param {Object} prevState 之前的状态
*/
emit(prevState) {
const currentState = this.deepClone(this.state);
this.listeners.forEach((listener, id) => {
try {
// 使用微任务异步执行,避免阻塞主线程
Promise.resolve().then(() => {
if (this.listeners.has(id)) {
listener(currentState, prevState);
}
}).catch(error => {
console.error(`[qiankun] Listener ${id.toString()} error:`, error);
});
} catch (error) {
console.error(`[qiankun] Listener ${id.toString()} error:`, error);
}
});
}
/**
* 深度合并状态
* @param {Object} target 目标对象
* @param {Object} source 源对象
*/
mergeState(target, source) {
const result = this.deepClone(target);
for (const key in source) {
if (source.hasOwnProperty(key)) {
const sourceValue = source[key];
const targetValue = result[key];
if (this.isPlainObject(sourceValue) && this.isPlainObject(targetValue)) {
// 递归合并对象
result[key] = this.mergeState(targetValue, sourceValue);
} else {
// 直接赋值
result[key] = this.deepClone(sourceValue);
}
}
}
return result;
}
/**
* 深度克隆对象
* @param {any} obj 要克隆的对象
*/
deepClone(obj) {
if (obj === null || typeof obj !== 'object') {
return obj;
}
if (obj instanceof Date) {
return new Date(obj.getTime());
}
if (obj instanceof Array) {
return obj.map(item => this.deepClone(item));
}
if (typeof obj === 'object') {
const clonedObj = {};
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
clonedObj[key] = this.deepClone(obj[key]);
}
}
return clonedObj;
}
}
/**
* 判断是否为纯对象
* @param {any} obj 要判断的对象
*/
isPlainObject(obj) {
return obj !== null &&
typeof obj === 'object' &&
Object.prototype.toString.call(obj) === '[object Object]';
}
/**
* 销毁全局状态管理器
*/
destroy() {
this.state = {};
this.listeners.clear();
this.initialized = false;
}
}
// 创建单例实例
let globalStateInstance = null;
function initGlobalState(initialState = {}) {
if (!globalStateInstance) {
globalStateInstance = new GlobalState();
}
return globalStateInstance.initGlobalState(initialState);
}
// 获取全局状态实例(用于调试)
function getGlobalStateInstance() {
return globalStateInstance;
}
export { initGlobalState, getGlobalStateInstance };
// main-app/src/micro-fe/state-bridge.js
import { initGlobalState } from 'qiankun';
class MainAppStateBridge {
constructor() {
this.actions = null;
this.subApps = new Map();
}
// 初始化全局状态
init(initialState) {
this.actions = initGlobalState(initialState);
// 监听自身状态变化
this.actions.onGlobalStateChange((state, prevState) => {
this.handleMainAppStateChange(state, prevState);
});
return this.actions;
}
// 为子应用创建状态桥接
createSubAppStateBridge(subAppName) {
if (!this.actions) {
throw new Error('Global state not initialized');
}
const subAppActions = {
...this.actions,
// 子应用特定的方法
getSubAppName: () => subAppName,
// 可以添加子应用级别的状态管理
setSubAppState: (state) => this.setSubAppState(subAppName, state)
};
this.subApps.set(subAppName, {
actions: subAppActions,
state: {}
});
return subAppActions;
}
// 处理主应用状态变化
handleMainAppStateChange(state, prevState) {
// 主应用自身的状态响应逻辑
this.updateMainAppUI(state);
// 记录状态变化日志
this.logStateChange('main-app', state, prevState);
}
// 设置子应用特定状态
setSubAppState(subAppName, state) {
const subApp = this.subApps.get(subAppName);
if (subApp) {
subApp.state = { ...subApp.state, ...state };
// 可以在这里实现子应用状态与全局状态的某种映射
this.maybeUpdateGlobalStateFromSubApp(subAppName, state);
}
}
// 可能根据子应用状态更新全局状态
maybeUpdateGlobalStateFromSubApp(subAppName, state) {
// 例如:当子应用的用户信息变化时,同步到全局状态
if (state.user) {
this.actions.setGlobalState({
user: state.user,
lastUpdatedBy: subAppName
});
}
}
// 更新主应用UI
updateMainAppUI(state) {
// 实现主应用界面更新逻辑
if (state.user) {
this.updateUserInfo(state.user);
}
if (state.theme) {
this.applyTheme(state.theme);
}
}
// 记录状态变化
logStateChange(source, state, prevState) {
if (process.env.NODE_ENV === 'development') {
console.group(`[qiankun] State changed from ${source}`);
console.log('Previous:', prevState);
console.log('Current:', state);
console.groupEnd();
}
}
}
// 主应用中使用
export const stateBridge = new MainAppStateBridge();
// 初始化全局状态
export const initAppGlobalState = (initialState) => {
return stateBridge.init(initialState);
};
// 为子应用提供状态桥接
export const getSubAppStateBridge = (subAppName) => {
return stateBridge.createSubAppStateBridge(subAppName);
};
// subapp/src/utils/global-state-adapter.js
class GlobalStateAdapter {
constructor(props) {
this.props = props;
this.state = {};
this.unsubscribe = null;
this.listeners = new Map();
}
// 初始化适配器
init() {
if (!this.props || !this.props.onGlobalStateChange) {
console.warn('[qiankun] Global state not available in sub-app');
return false;
}
// 监听全局状态变化
this.unsubscribe = this.props.onGlobalStateChange((state, prevState) => {
this.handleGlobalStateChange(state, prevState);
}, true); // 立即执行一次获取初始状态
return true;
}
// 处理全局状态变化
handleGlobalStateChange(state, prevState) {
const prevLocalState = { ...this.state };
this.state = state;
// 通知所有本地监听器
this.notifyLocalListeners(state, prevState);
// 执行子应用特定的状态处理
this.handleSubAppSpecificChanges(state, prevState);
// 更新子应用UI
this.updateSubAppUI(state, prevState);
}
// 设置全局状态(代理方法)
setGlobalState(state) {
if (this.props && this.props.setGlobalState) {
return this.props.setGlobalState(state);
}
return false;
}
// 获取当前状态
getGlobalState() {
return this.props ? this.props.getGlobalState() : this.state;
}
// 注册本地监听器(子应用内部使用)
onStateChange(callback, immediately = false) {
const listenerId = Symbol('local-state-listener');
this.listeners.set(listenerId, callback);
if (immediately) {
try {
callback(this.state, this.state);
} catch (error) {
console.error('Local state listener error:', error);
}
}
return () => {
this.listeners.delete(listenerId);
};
}
// 通知本地监听器
notifyLocalListeners(state, prevState) {
this.listeners.forEach((listener, id) => {
try {
setTimeout(() => {
if (this.listeners.has(id)) {
listener(state, prevState);
}
}, 0);
} catch (error) {
console.error(`Local listener ${id.toString()} error:`, error);
}
});
}
// 处理子应用特定的状态变化
handleSubAppSpecificChanges(state, prevState) {
// 用户信息变化
if (state.user !== prevState.user) {
this.handleUserChange(state.user, prevState.user);
}
// 主题变化
if (state.theme !== prevState.theme) {
this.handleThemeChange(state.theme);
}
// 权限变化
if (state.user?.permissions !== prevState.user?.permissions) {
this.handlePermissionChange(state.user?.permissions);
}
}
// 更新子应用UI
updateSubAppUI(state, prevState) {
// 实现子应用界面更新逻辑
// 例如:更新用户信息显示、应用主题等
}
// 具体的状态处理函数
handleUserChange(user, prevUser) {
console.log('User changed:', { from: prevUser, to: user });
// 更新用户相关的界面和状态
}
handleThemeChange(theme) {
document.documentElement.setAttribute('data-theme', theme);
}
handlePermissionChange(permissions) {
// 根据新权限更新界面和功能
}
// 销毁适配器
destroy() {
if (this.unsubscribe) {
this.unsubscribe();
}
this.listeners.clear();
}
}
// 在子应用中使用
export const createGlobalStateAdapter = (props) => {
const adapter = new GlobalStateAdapter(props);
if (adapter.init()) {
return adapter;
}
return null;
};
// 状态变更传播示意图
/**
*
* 主应用 setGlobalState({user: newUser})
* ↓
* GlobalStateManager.notifyListeners()
* ↓
* 主应用监听器 ───→ 子应用A监听器 ───→ 子应用B监听器
* ↓ ↓ ↓
* 更新主应用UI 更新子应用AUI 更新子应用BUI
*
*/
// 通信过程跟踪
class CommunicationTracker {
constructor() {
this.messageId = 0;
this.communicationLog = [];
}
trackStateChange(source, target, state, action) {
const logEntry = {
id: ++this.messageId,
timestamp: Date.now(),
source,
target,
state: this.sanitizeState(state),
action,
duration: null
};
this.communicationLog.push(logEntry);
if (process.env.NODE_ENV === 'development') {
console.log(`[qiankun-comm] ${source} -> ${target}:`, action, state);
}
return logEntry.id;
}
markCompletion(messageId, success = true) {
const entry = this.communicationLog.find(log => log.id === messageId);
if (entry) {
entry.duration = Date.now() - entry.timestamp;
entry.success = success;
}
}
sanitizeState(state) {
// 移除敏感信息
const sanitized = { ...state };
if (sanitized.user) {
sanitized.user = { ...sanitized.user };
delete sanitized.user.password;
delete sanitized.user.token;
}
return sanitized;
}
getCommunicationStats() {
const successful = this.communicationLog.filter(log => log.success);
const failed = this.communicationLog.filter(log => log.success === false);
return {
total: this.communicationLog.length,
successful: successful.length,
failed: failed.length,
averageDuration: successful.reduce((sum, log) => sum + log.duration, 0) / successful.length,
recentMessages: this.communicationLog.slice(-10)
};
}
}
// 在全局状态管理器中集成跟踪
class TrackedGlobalState extends GlobalState {
constructor() {
super();
this.tracker = new CommunicationTracker();
}
setGlobalState(state, overwrite = false) {
const messageId = this.tracker.trackStateChange(
'main-app',
'all',
state,
'setGlobalState'
);
try {
const result = super.setGlobalState(state, overwrite);
this.tracker.markCompletion(messageId, result);
return result;
} catch (error) {
this.tracker.markCompletion(messageId, false);
throw error;
}
}
}
发布-订阅模式:基于事件的通知机制
中心化状态存储:单一数据源
状态隔离:主应用和子应用的状态操作隔离
异步通知:使用微任务避免阻塞
状态变更传播:主应用 → 所有监听器(包括子应用)
双向通信:子应用也可以更新全局状态
状态合并:智能合并而不是完全覆盖
错误隔离:单个监听器错误不影响其他监听器
懒执行:使用 setTimeout 和 Promise 避免阻塞
深度克隆:确保状态不可变性
内存管理:提供清理和销毁方法
条件监听:支持立即执行和延迟执行
通过这种设计,Qiankun 实现了高效、可靠的主应用与子应用之间的状态通信,同时保持了良好的性能和可维护性。