«Эта статья участвовала в мероприятии Haowen Convocation Order, щелкните, чтобы просмотреть:Двойные заявки на внутреннюю и внешнюю стороны, призовой фонд в 20 000 юаней ждет вас, чтобы бросить вызов!"
предисловие
Среди микроэлементов спереди, песочница очень важная вещь. Передняя рамка как микроsingle-spadocument,locationи т. Д. Объекты. В процессе разработки поддержания несколько команд могут работать над этим, и трудно ограничить их использовать глобальные переменные. Некоторые страницы могут иметь несколько различных поддержаний, нам нужно поддерживать несколько песочбок, и каждая песочница должна иметь возможность загружать, выгружать и восстановить.
iframe
contentWindow
let iframe = document.createElement('iframe',{src:'about:blank'});
document.body.appendChild(iframe);
const sandboxGlobal = iframe.contentWindow;
contentWindow, src iframe установлен наabout:blank, можно гарантировать, что он должен находиться в том же домене, и загрузки ресурсов не произойдет, см.iframe src
В предисловии мы упомянули, что в дополнение к изолированной оконной среде, микро-фронтенду на самом деле необходимо совместно использовать некоторые глобальные объекты.На данный момент для этого мы можем использовать прокси. Давайте посмотрим на код ниже
class SandboxWindow {
/**
* 构造函数
* @param {*} context 需要共享的对象
* @param {*} frameWindow iframe的window
*/
constructor(context, frameWindow) {
return new Proxy(frameWindow, {
get(target, name) {
if (name in context) { // 优先使用共享对象
return context[name];
}
return target[name];
},
set(target, name, value) {
if (name in context) { // 修改共享对象的值
return context[name] = value;
}
target[name] = value;
}
})
}
}
// 需要全局共享的变量
const context = { document:window.document, history: window.history }
// 创建沙箱
const newSandboxWindow = new SandboxWindow(context, sandboxGlobal);
// 判断沙箱上的对象和全局对象是否相等
console.log('equal',newSandboxWindow.document === window.document)
newSandboxWindow.abc = '1'; //在沙箱上添加属性
console.log(window.abc); // 在全局上查看属性
console.log(newSandboxWindow.abc) //在沙箱上查看属性
Давайте запустим и посмотрите результат
- Несколько экземпляров, несколько независимых микроприложений работают одновременно.
diffспособ реализации песочницы
В браузерах, не поддерживающих прокси, мы можем попрактиковаться в песочнице с помощью diff. Сохранение объекта окна моментального снимка во время работы приложения, копирование всех свойств текущего объекта окна в объект моментального снимка, изменение объекта окна как различия при удалении субприложения и использование других свойств в качестве различийmodifyMapСохраните его и добавьте эти измененные свойства при повторном монтировании. код показывает, как показано ниже:
class DiffSandbox {
constructor(name) {
this.name = name;
this.modifyMap = {}; // 存放修改的属性
this.windowSnapshot = {};
}
active() {
// 缓存active状态的沙箱
this.windowSnapshot = {};
for (const item in window) {
this.windowSnapshot[item] = window[item];
}
Object.keys(this.modifyMap).forEach(p => {
window[p] = this.modifyMap[p];
})
}
inactive() {
for (const item in window) {
if (this.windowSnapshot[item] !== window[item]) {
// 记录变更
this.modifyMap[item] = window[item];
// 还原window
window[item] = this.windowSnapshot[item];
}
}
}
}
const diffSandbox = new DiffSandbox('diff沙箱');
diffSandbox.active(); // 激活沙箱
window.a = '1'
console.log('开启沙箱:',window.a);
diffSandbox.inactive(); //失活沙箱
console.log('失活沙箱:', window.a);
diffSandbox.active(); // 重新激活
console.log('再次激活', window.a);
Запустим и посмотрим на результаты
Этот подход не может поддерживать несколько экземпляров, поскольку все атрибуты во время работы сохраняются в Window.
Действующий на(Proxy)Реализовать изолированную программную среду с одним экземпляром
В ES6 мы можем использовать прокси(Proxy)Реализовать захват объекта. Базовая запись также записывается путем изменения объекта окна, удаления этих записей при удалении и восстановления этих записей при повторной активации приложения для достижения цели имитации среды песочницы. код показывает, как показано ниже
// 修改window属性的公共方法
const updateWindowProp = (prop, value, isDel) => {
if (value === undefined || isDel) {
delete window[prop];
} else {
window[prop] = value;
}
}
class ProxySandbox {
active() {
// 根据记录还原沙箱
this.currentUpdatedPropsValueMap.forEach((v, p) => updateWindowProp(p, v));
}
inactive() {
// 1 将沙箱期间修改的属性还原为原先的属性
this.modifiedPropsMap.forEach((v, p) => updateWindowProp(p, v));
// 2 将沙箱期间新增的全局变量消除
this.addedPropsMap.forEach((_, p) => updateWindowProp(p, undefined, true));
}
constructor(name) {
this.name = name;
this.proxy = null;
// 存放新增的全局变量
this.addedPropsMap = new Map();
// 存放沙箱期间更新的全局变量
this.modifiedPropsMap = new Map();
// 存在新增和修改的全局变量,在沙箱激活的时候使用
this.currentUpdatedPropsValueMap = new Map();
const { addedPropsMap, currentUpdatedPropsValueMap, modifiedPropsMap } = this;
const fakeWindow = Object.create(null);
const proxy = new Proxy(fakeWindow, {
set(target, prop, value) {
if (!window.hasOwnProperty(prop)) {
// 如果window上没有的属性,记录到新增属性里
// debugger;
addedPropsMap.set(prop, value);
} else if (!modifiedPropsMap.has(prop)) {
// 如果当前window对象有该属性,且未更新过,则记录该属性在window上的初始值
const originalValue = window[prop];
modifiedPropsMap.set(prop, originalValue);
}
// 记录修改属性以及修改后的值
currentUpdatedPropsValueMap.set(prop, value);
// 设置值到全局window上
updateWindowProp(prop, value);
return true;
},
get(target, prop) {
return window[prop];
},
});
this.proxy = proxy;
}
}
const newSandBox = new ProxySandbox('代理沙箱');
const proxyWindow = newSandBox.proxy;
proxyWindow.a = '1'
console.log('开启沙箱:', proxyWindow.a, window.a);
newSandBox.inactive(); //失活沙箱
console.log('失活沙箱:', proxyWindow.a, window.a);
newSandBox.active(); //失活沙箱
console.log('重新激活沙箱:', proxyWindow.a, window.a);
Запустим код и посмотрим результат
Таким образом, одновременно может быть только одна активная песочница, иначе переменные глобального объекта будут обновляться более чем двумя песочницами, что приведет к конфликтам глобальных переменных.
на основе прокси(Proxy)Песочница с несколькими экземплярами
В сценарии с одним экземпляром наш fakeWindow представляет собой пустой объект без какой-либо функции хранения переменных.Переменные, созданные микроприложением, на самом деле монтируются в окне, что ограничивает их не может быть двух одновременно.Активированные микроприложения.
class MultipleProxySandbox {
active() {
this.sandboxRunning = true;
}
inactive() {
this.sandboxRunning = false;
}
/**
* 构造函数
* @param {*} name 沙箱名称
* @param {*} context 共享的上下文
* @returns
*/
constructor(name, context = {}) {
this.name = name;
this.proxy = null;
const fakeWindow = Object.create({});
const proxy = new Proxy(fakeWindow, {
set: (target, name, value) => {
if (this.sandboxRunning) {
if (Object.keys(context).includes(name)) {
context[name] = value;
}
target[name] = value;
}
},
get: (target, name) => {
// 优先使用共享对象
if (Object.keys(context).includes(name)) {
return context[name];
}
return target[name];
}
})
this.proxy = proxy;
}
}
const context = { document: window.document };
const newSandBox1 = new MultipleProxySandbox('代理沙箱1', context);
newSandBox1.active();
const proxyWindow1 = newSandBox1.proxy;
const newSandBox2 = new MultipleProxySandbox('代理沙箱2', context);
newSandBox2.active();
const proxyWindow2 = newSandBox2.proxy;
console.log('共享对象是否相等', window.document === proxyWindow1.document, window.document === proxyWindow2.document);
proxyWindow1.a = '1'; // 设置代理1的值
proxyWindow2.a = '2'; // 设置代理2的值
window.a = '3'; // 设置window的值
console.log('打印输出的值', proxyWindow1.a, proxyWindow2.a, window.a);
newSandBox1.inactive(); newSandBox2.inactive(); // 两个沙箱都失活
proxyWindow1.a = '4'; // 设置代理1的值
proxyWindow2.a = '4'; // 设置代理2的值
window.a = '4'; // 设置window的值
console.log('失活后打印输出的值', proxyWindow1.a, proxyWindow2.a, window.a);
newSandBox1.active(); newSandBox2.active(); // 再次激活
proxyWindow1.a = '4'; // 设置代理1的值
proxyWindow2.a = '4'; // 设置代理2的值
window.a = '4'; // 设置window的值
console.log('失活后打印输出的值', proxyWindow1.a, proxyWindow2.a, window.a);
Запустив код, результат выглядит следующим образом:
Таким образом, одновременно может быть только одна активная несколько песочниц, что реализует многоэкземплярные песочницы.
заключительные замечания
Выше приведены наиболее часто используемые реализации микро-фронтендов в песочнице.Если мы хотим использовать их в производстве, нам нужно сделать много суждений и ограничений. Пожалуйста, смотрите следующую статьюИнтерпретация исходного кода песочницы qiankun, чтобы увидеть, как реализована структура. Приведенный выше код находится на github, если вы хотите его просмотреть, переместитеjs-sandbox
Ссылаться на
Если вы считаете, что эта статья хороша, вы можете также
1,подобно, чтобы больше людей могли увидеть этот контент
2,Подписывайтесь на меня, пусть будут долгосрочные отношения
3. Подпишитесь на официальный аккаунт »Фронтенду есть что сказать», в ней много оригинальных статей и средств разработки, приветствую ваше внимание, и читайте мои статьи как можно скорее