不同模块的数据通信共享如何做的?
- 场景:这是一个Monorepo+微前端项目,需要在几个子系统和之间共享关键数据。 然后麻烦的点是,这几个子系统的基座系统,不全是同一个,然后,也不全在这个Monorepo当中。在我来这个项目之前,我mt当时是考虑了这个仓库的体积,以及时间成本,就没有全部迁移过来。
总结一下背景就是:有多个基座
好了背景说完了。现在我有这么几种方案:
基于微前端注入的window全局对象:
- 会污染全局空间,并且没有响应式
- 任何地方都能修改,难以追溯和调试
- 在不同基座的系统中,也不好传递
基于 localStorage / sessionStorage
- 浏览器天然支持,兼容性好
- 但是
- 同步阻塞,无响应式,还有容量限制
基于共享的MobX Store、Zustand等等
- 只需要主应用发布实例,然后通过webpack5的模块邦联模式进行远程共享即可
这里有一个问题?如何确保远程共享的实例是同一个?
答:使用模块邦联的shared,它会确保只要只有一个实例被加载和执行,即使有不同的基座,也可以。
而且模块邦联模式,可以做到与技术栈、代码仓库位置、甚至部署环境都完全解耦。
- 只需要主应用发布实例,然后通过webpack5的模块邦联模式进行远程共享即可
最终方案:因为其中几个包特别大,再多一个包是需要仔细考虑的。其次,这个场景下,要同步的数据并不太多,所以应该遵循怎么简单怎么来的原则。
所以还是选择了localStorage / sessionStorage,因为它最简单直接。
但是,如果我来设计的话,可以混合CustomEvent封装一个发布订阅模式,然后再要扩展的话,
js
// A lightweight wrapper for localStorage communication
class SharedState {
set(key, value) {
const data = JSON.stringify(value);
localStorage.setItem(key, data);
// Manually dispatch an event for same-tab communication
window.dispatchEvent(new CustomEvent('shared-state-change', {
detail: { key, value }
}));
}
get(key) {
const data = localStorage.getItem(key);
return data ? JSON.parse(data) : null;
}
// Allow other apps to subscribe to changes
subscribe(key, callback) {
const handler = (event) => {
if (event.detail && event.detail.key === key) {
callback(event.detail.value);
}
};
window.addEventListener('shared-state-change', handler);
// Return an unsubscribe function
return () => window.removeEventListener('shared-state-change', handler);
}
}
// Export a singleton instance
export const sharedState = new SharedState();
即使在业务上落地比较复杂,要考虑很多东西,描述起来也比较简单,前端的工作往往是这样。所以我后面的讲述尽量放在一个具体的场景里面,来显示我的一些方案选择。