mustard-app
Version:
个人前端微应用建设中。。。
139 lines (128 loc) • 5.5 kB
text/typescript
import { ProxyEventListener }from './proxyEventListener';
import { proxyDocument }from './proxyDocument';
import { proxyHistory }from './proxyHistory';
import { proxyLocation }from './proxyLocation';
import { proxyLocalStorage, proxySessionStorage }from './proxyStorage';
import { MustardName, MustardURL } from '../typings';
import { EventCenterMicroApp } from '../communication';
export class SandBox {
active = false; // 沙箱是否在运行
microWindow = {}; // 代理的对象
injectedKeys = new Set<string | symbol>(); // 新添加的属性,在卸载时清空
name:MustardName; // 沙箱标识同app标识一致
proxyEventListener:ProxyEventListener; // 全局事件代理
proxyWindow; // window 代理
proxyDocument; // document 代理
proxyHistory; // history 代理
proxyLocation; // location 代理
proxyLocalStorage; // localStorage 代理
proxySessionStorage; // sessionStorage 代理
microApp: EventCenterMicroApp; // 事件通讯
// todo
// url: MustardURL
constructor (name:MustardName, url: MustardURL) {
this.name = name;
this.proxyLocation = proxyLocation(this.name, url);
this.proxyHistory = proxyHistory(this.name);
this.proxyLocalStorage = proxyLocalStorage(this.name);
this.proxySessionStorage = proxySessionStorage(this.name);
this.proxyDocument = proxyDocument(this.name);
this.proxyEventListener = new ProxyEventListener();
this.microApp = new EventCenterMicroApp(this.name);
this.proxyWindow = new Proxy(this.microWindow, {
// 取值
get: (target, key) => {
// 优先从代理对象上取值
if (Reflect.has(target, key)) {
return Reflect.get(target, key);
}
if(key === 'document') {
return this.proxyDocument;
}
if(key === 'addEventListener') {
return this.proxyEventListener.addEventListener.bind(this.proxyEventListener);
}
if(key === 'history') {
return this.proxyHistory;
}
if(key === 'location') {
return this.proxyLocation;
}
if(key === 'localStorage') {
return this.proxyLocalStorage;
}
if(key === 'sessionStorage') {
return this.proxySessionStorage;
}
if(key === 'microApp') {
return this.microApp;
}
// 否则兜底到window对象上取值
const rawValue = Reflect.get(window, key);
// 如果兜底的值为函数,则需要绑定window对象,如:console、alert等
if (typeof rawValue === 'function') {
const valueStr = rawValue.toString();
// 排除构造函数
if (!/^function\s+[A-Z]/.test(valueStr) && !/^class\s+/.test(valueStr)) {
return rawValue.bind(window);
}
}
// 其它情况直接返回
return rawValue;
},
// 设置变量
set: (target, key, value) => {
// 沙箱只有在运行时可以设置变量
if (this.active) {
Reflect.set(target, key, value);
// 记录添加的变量,用于后续清空操作
this.injectedKeys.add(key);
}
return true;
},
deleteProperty: (target, key) => {
// 当前key存在于代理对象上时才满足删除条件
if (Object.prototype.hasOwnProperty.call(target, key)) {
return Reflect.deleteProperty(target, key);
}
return true;
},
has (target, key) {
return key in target || key in window;
}
});
}
start () {
if(!this.active) {
this.active = true;
}
}
stop () {
if(this.active) {
this.microApp.clearDateListener();
this.active = false;
Array.from(this.injectedKeys.keys()).forEach(key => Reflect.deleteProperty(this.microWindow, key));
this.injectedKeys.clear();
this.proxyEventListener.clear();
}
}
// 修改js作用域
bindScope (code) {
return `
;(function(window, self){
const microApp = window.microApp;
const history = window.history;
const location = window.location;
const document = window.document;
const localStorage = window.localStorage;
const sessionStorage = window.sessionStorage;
const addEventListener = window.addEventListener;
${code}\n;
}).call(
mustardAppInfos.getAppProxyWindow('${this.name}'),
mustardAppInfos.getAppProxyWindow('${this.name}'),
mustardAppInfos.getAppProxyWindow('${this.name}'),
)
`;
}
}