提出背景
当前项目采用微前端架构,各个应用通过iframe嵌入,有时候不同应用间需要通信,会采用localstorage;且不同应用内部可能会有部分本地存储的需求,比如列配置,这样单个应用内部以及应用间可能会出现key重复,导致出现值覆盖的问题,从而出现未知bug
解决方案
命名规范示例:应用_模块_业务名称 (TEST_SHARE_userInfo)。
**解释:**有个名为test的应用中有一个share模块,该模块中有一个userInfo需要持久化存储,
- 考虑到不同项目前可能会有相同可以,所以项目名作为前缀。
- 应用内部不同业务模块可能有重复key,所以再采用业务名作为次前缀
- 原key采用小驼峰
- 前缀建议大写,前缀间,前缀和可以key之间采用
_链接
当前阶段现状
- 旧项目对localstorage使用极多,每个地方均手动处理前缀工程量巨大
- 频繁添加前缀容易拼接出错
- 考虑将来扩展性,localstorage使用频率,localstorage的限制,及JSON序列化时的安全性问题
综上所诉,建议对localstorage进行封装。
Storage封装
功能分析
- 需要支持全局配置应用名作为默认应用前缀(项目级)
- 需要支持Storage实例灵活配置默认模块前缀(模块级)
- get或set key 时需要支持配置即时应用前缀和模块前缀(实时)
- 配置优先级:实时 > 模块级 > 项目级
- get 和 set 封装后应当支持直接存入对象、获取对象,不应还需要序列化或反序列化,如果涉及sessionStorage,还可配置失效时间
- get set 需要解决序列化安全问题
- 需要能灵活应用上述配置,解决不同应用间key冲突问题,并可以自动准确获取值
功能使用设计
假设窝门有appA和appB两款应用,它们均有功能模块moduleA, moduleB,各个模块均有userInfo需要持久化存储。结构关系如下:
const relation = {
appA:{
moduleA: {
usaerInfo: {}
},
moduleB: {
usaerInfo: {}
}
},
appB:{
moduleA: {
usaerInfo: {}
},
moduleB: {
usaerInfo: {}
}
}
}
则可在main.ts中进行如下配置:
// appA/main.ts
import Storage from "customStorage";
Storage.use({appName: "APPA"});
// appB/main.ts
import Storage from "customStorage";
Storage.use({appName: "APPB"});
则可对两个应用共4个模块做如下配置,且其取值关系如下
// appA/moduleA
import Storage from "customStorage";
const storage = new Storage({moduleName: 'MODULEA'});
storage.get('userinfo'); // 应用A模块A的userInfo
storage.get('userinfo', {moduleName: 'MODULEB'}); // 应用A模块B的userInfo
storage.get('userinfo', {appName:'APPB', moduleName: 'MODULEB'}); // 应用B模块B的userInfo
// appA/moduleB
import Storage from "customStorage";
const storage = new Storage({moduleName: 'MODULEB'});
// appB/moduleA
import Storage from "customStorage";
const storage = new Storage({moduleName: 'MODULEA'});
// appB/moduleB
import Storage from "customStorage";
const storage = new Storage({moduleName: 'MODULEB'});
未来进一步设计
剔除字符串拼接,更改为nameSpace方案,防止localstorage key过多; (具体设计体现在storage封装细节,待定)
再进一步设计
全面禁止直接使用storage,仅限微前端和持久化使用,且应当交由store 与各sotre插件适配,待storage完善后处理