微前端
微前端, 类似于微服务概念,可以满足多个应用可以独立开发,测试,部署,然后可以整合到一个应用中,对外交互还是一个整体;
资源隔离
要实现微前端,应用在运行时加载,并且多个应用同时共存时,需要解决资源隔离。资源隔离分为,css资源和js资源
css资源隔离
shadow DOM
- 基于web component shadow DOM shadow dom
CSS scope
- css隔离方案类似 vue scope
- css.process, 遍历每个样式表, 为每个css规则添加上前缀
js资源隔离
iframe
- iframe具有天然隔离的能力,css隔离,js隔离,但是有以下缺点,在腾讯推出的wujie微前端架构中采用了这一方案,解决相关副作用。
- 无界
- 缺点:
- 路由状态丢失,刷新一下,iframe的url状态就丢失了;
- dom割裂严重,弹窗只能在iframe内部展示,无法覆盖全局
- 每次打开白屏时间太长,对于spa应该不能结束;
- 缺点:
沙箱隔离
- 以qiankun为代表的两种js沙箱机制
- sandbox沙箱——只适合单一的子应用,
- 激活将window上的属性遍历,暂存到windowSnapshot上,激活时修改的属性也存放到window, 删除的属性删除;
- 未激活,diff,将修改属性和删除属性暂存起来;
- sandbox沙箱——只适合单一的子应用,
/**
* @author Hydrogen
* @since 2020-3-8
*/
import type { SandBox } from '../interfaces';
import { SandBoxType } from '../interfaces';
function iter(obj: typeof window | Record<any, any>, callbackFn: (prop: any) => void) {
for (const prop in obj) {
if (obj.hasOwnProperty(prop) || prop === 'clearInterval') {
callbackFn(prop);
}
}
}
/**
* 基于 diff 方式实现的沙箱,用于不支持 Proxy 的低版本浏览器
*/
export default class SnapshotSandbox implements SandBox {
proxy: WindowProxy;
name: string;
type: SandBoxType;
sandboxRunning = true;
private windowSnapshot!: Window;
private modifyPropsMap: Record<any, any> = {};
private deletePropsSet: Set<any> = new Set();
constructor(name: string) {
this.name = name;
this.proxy = window;
this.type = SandBoxType.Snapshot;
}
active() {
// 记录当前快照
this.windowSnapshot = {} as Window;
iter(window, (prop) => {
this.windowSnapshot[prop] = window[prop];
});
// 恢复之前的变更
Object.keys(this.modifyPropsMap).forEach((p: any) => {
window[p] = this.modifyPropsMap[p];
});
// 删除之前删除的属性
this.deletePropsSet.forEach((p: any) => {
delete window[p];
});
this.sandboxRunning = true;
}
inactive() {
this.modifyPropsMap = {};
this.deletePropsSet.clear();
iter(window, (prop) => {
if (window[prop] !== this.windowSnapshot[prop]) {
// 记录变更,恢复环境
this.modifyPropsMap[prop] = window[prop];
window[prop] = this.windowSnapshot[prop];
}
});
iter(this.windowSnapshot, (prop) => {
if (!window.hasOwnProperty(prop)) {
// 记录被删除的属性,恢复环境
this.deletePropsSet.add(prop);
window[prop] = this.windowSnapshot[prop];
}
});
this.sandboxRunning = false;
}
patchDocument(): void {}
}
- proxySandbox沙箱
- proxy了createFakeWindow的set, get, has, definedperproty等方法;
- 而FakeWindow是通过复制了window上的document、location、top、window拷贝了一份;
- 真正做到了不污染window, 并且支持多实例;