NuclearDispersionSystem/ant-design-vue-jeecg/node_modules/qiankun/lib/sandbox/proxySandbox.js
2023-09-14 14:47:11 +08:00

367 lines
14 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
var _interfaces = require("../interfaces");
var _utils = require("../utils");
var _common = require("./common");
/**
* fastest(at most time) unique array method
* @see https://jsperf.com/array-filter-unique/30
*/
function uniq(array) {
return array.filter(function filter(element) {
return element in this ? false : this[element] = true;
}, Object.create(null));
} // zone.js will overwrite Object.defineProperty
var rawObjectDefineProperty = Object.defineProperty;
var variableWhiteListInDev = process.env.NODE_ENV === 'development' || window.__QIANKUN_DEVELOPMENT__ ? [// for react hot reload
// see https://github.com/facebook/create-react-app/blob/66bf7dfc43350249e2f09d138a20840dae8a0a4a/packages/react-error-overlay/src/index.js#L180
'__REACT_ERROR_OVERLAY_GLOBAL_HOOK__'] : []; // who could escape the sandbox
var variableWhiteList = [// FIXME System.js used a indirect call with eval, which would make it scope escape to global
// To make System.js works well, we write it back to global window temporary
// see https://github.com/systemjs/systemjs/blob/457f5b7e8af6bd120a279540477552a07d5de086/src/evaluate.js#L106
'System', // see https://github.com/systemjs/systemjs/blob/457f5b7e8af6bd120a279540477552a07d5de086/src/instantiate.js#L357
'__cjsWrapper'].concat(variableWhiteListInDev);
/*
variables who are impossible to be overwrite need to be escaped from proxy sandbox for performance reasons
*/
var unscopables = {
undefined: true,
Array: true,
Object: true,
String: true,
Boolean: true,
Math: true,
Number: true,
Symbol: true,
parseFloat: true,
Float32Array: true,
isNaN: true,
Infinity: true,
Reflect: true,
Float64Array: true,
Function: true,
Map: true,
NaN: true,
Promise: true,
Proxy: true,
Set: true,
parseInt: true,
requestAnimationFrame: true
};
var useNativeWindowForBindingsProps = new Map([['fetch', true], ['mockDomAPIInBlackList', process.env.NODE_ENV === 'test']]);
function createFakeWindow(globalContext) {
// map always has the fastest performance in has check scenario
// see https://jsperf.com/array-indexof-vs-set-has/23
var propertiesWithGetter = new Map();
var fakeWindow = {};
/*
copy the non-configurable property of global to fakeWindow
see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy/handler/getOwnPropertyDescriptor
> A property cannot be reported as non-configurable, if it does not exists as an own property of the target object or if it exists as a configurable own property of the target object.
*/
Object.getOwnPropertyNames(globalContext).filter(function (p) {
var descriptor = Object.getOwnPropertyDescriptor(globalContext, p);
return !(descriptor === null || descriptor === void 0 ? void 0 : descriptor.configurable);
}).forEach(function (p) {
var descriptor = Object.getOwnPropertyDescriptor(globalContext, p);
if (descriptor) {
var hasGetter = Object.prototype.hasOwnProperty.call(descriptor, 'get');
/*
make top/self/window property configurable and writable, otherwise it will cause TypeError while get trap return.
see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy/handler/get
> The value reported for a property must be the same as the value of the corresponding target object property if the target object property is a non-writable, non-configurable data property.
*/
if (p === 'top' || p === 'parent' || p === 'self' || p === 'window' || process.env.NODE_ENV === 'test' && (p === 'mockTop' || p === 'mockSafariTop')) {
descriptor.configurable = true;
/*
The descriptor of window.window/window.top/window.self in Safari/FF are accessor descriptors, we need to avoid adding a data descriptor while it was
Example:
Safari/FF: Object.getOwnPropertyDescriptor(window, 'top') -> {get: function, set: undefined, enumerable: true, configurable: false}
Chrome: Object.getOwnPropertyDescriptor(window, 'top') -> {value: Window, writable: false, enumerable: true, configurable: false}
*/
if (!hasGetter) {
descriptor.writable = true;
}
}
if (hasGetter) propertiesWithGetter.set(p, true); // freeze the descriptor to avoid being modified by zone.js
// see https://github.com/angular/zone.js/blob/a5fe09b0fac27ac5df1fa746042f96f05ccb6a00/lib/browser/define-property.ts#L71
rawObjectDefineProperty(fakeWindow, p, Object.freeze(descriptor));
}
});
return {
fakeWindow: fakeWindow,
propertiesWithGetter: propertiesWithGetter
};
}
var activeSandboxCount = 0;
/**
* 基于 Proxy 实现的沙箱
*/
var ProxySandbox = /*#__PURE__*/function () {
function ProxySandbox(name) {
var _this = this;
var globalContext = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : window;
(0, _classCallCheck2.default)(this, ProxySandbox);
/** window 值变更记录 */
this.updatedValueSet = new Set();
this.sandboxRunning = true;
this.latestSetProp = null;
this.name = name;
this.globalContext = globalContext;
this.type = _interfaces.SandBoxType.Proxy;
var updatedValueSet = this.updatedValueSet;
var _createFakeWindow = createFakeWindow(globalContext),
fakeWindow = _createFakeWindow.fakeWindow,
propertiesWithGetter = _createFakeWindow.propertiesWithGetter;
var descriptorTargetMap = new Map();
var hasOwnProperty = function hasOwnProperty(key) {
return fakeWindow.hasOwnProperty(key) || globalContext.hasOwnProperty(key);
};
var proxy = new Proxy(fakeWindow, {
set: function set(target, p, value) {
if (_this.sandboxRunning) {
_this.registerRunningApp(name, proxy); // We must kept its description while the property existed in globalContext before
if (!target.hasOwnProperty(p) && globalContext.hasOwnProperty(p)) {
var descriptor = Object.getOwnPropertyDescriptor(globalContext, p);
var writable = descriptor.writable,
configurable = descriptor.configurable,
enumerable = descriptor.enumerable;
if (writable) {
Object.defineProperty(target, p, {
configurable: configurable,
enumerable: enumerable,
writable: writable,
value: value
});
}
} else {
// @ts-ignore
target[p] = value;
}
if (variableWhiteList.indexOf(p) !== -1) {
// @ts-ignore
globalContext[p] = value;
}
updatedValueSet.add(p);
_this.latestSetProp = p;
return true;
}
if (process.env.NODE_ENV === 'development') {
console.warn("[qiankun] Set window.".concat(p.toString(), " while sandbox destroyed or inactive in ").concat(name, "!"));
} // 在 strict-mode 下Proxy 的 handler.set 返回 false 会抛出 TypeError在沙箱卸载的情况下应该忽略错误
return true;
},
get: function get(target, p) {
_this.registerRunningApp(name, proxy);
if (p === Symbol.unscopables) return unscopables; // avoid who using window.window or window.self to escape the sandbox environment to touch the really window
// see https://github.com/eligrey/FileSaver.js/blob/master/src/FileSaver.js#L13
if (p === 'window' || p === 'self') {
return proxy;
} // hijack globalWindow accessing with globalThis keyword
if (p === 'globalThis') {
return proxy;
}
if (p === 'top' || p === 'parent' || process.env.NODE_ENV === 'test' && (p === 'mockTop' || p === 'mockSafariTop')) {
// if your master app in an iframe context, allow these props escape the sandbox
if (globalContext === globalContext.parent) {
return proxy;
}
return globalContext[p];
} // proxy.hasOwnProperty would invoke getter firstly, then its value represented as globalContext.hasOwnProperty
if (p === 'hasOwnProperty') {
return hasOwnProperty;
}
if (p === 'document') {
return document;
}
if (p === 'eval') {
return eval;
}
var value = propertiesWithGetter.has(p) ? globalContext[p] : p in target ? target[p] : globalContext[p];
/* Some dom api must be bound to native window, otherwise it would cause exception like 'TypeError: Failed to execute 'fetch' on 'Window': Illegal invocation'
See this code:
const proxy = new Proxy(window, {});
const proxyFetch = fetch.bind(proxy);
proxyFetch('https://qiankun.com');
*/
var boundTarget = useNativeWindowForBindingsProps.get(p) ? _utils.nativeGlobal : globalContext;
return (0, _common.getTargetValue)(boundTarget, value);
},
// trap in operator
// see https://github.com/styled-components/styled-components/blob/master/packages/styled-components/src/constants.js#L12
has: function has(target, p) {
return p in unscopables || p in target || p in globalContext;
},
getOwnPropertyDescriptor: function getOwnPropertyDescriptor(target, p) {
/*
as the descriptor of top/self/window/mockTop in raw window are configurable but not in proxy target, we need to get it from target to avoid TypeError
see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy/handler/getOwnPropertyDescriptor
> A property cannot be reported as non-configurable, if it does not exists as an own property of the target object or if it exists as a configurable own property of the target object.
*/
if (target.hasOwnProperty(p)) {
var descriptor = Object.getOwnPropertyDescriptor(target, p);
descriptorTargetMap.set(p, 'target');
return descriptor;
}
if (globalContext.hasOwnProperty(p)) {
var _descriptor = Object.getOwnPropertyDescriptor(globalContext, p);
descriptorTargetMap.set(p, 'globalContext'); // A property cannot be reported as non-configurable, if it does not exists as an own property of the target object
if (_descriptor && !_descriptor.configurable) {
_descriptor.configurable = true;
}
return _descriptor;
}
return undefined;
},
// trap to support iterator with sandbox
ownKeys: function ownKeys(target) {
return uniq(Reflect.ownKeys(globalContext).concat(Reflect.ownKeys(target)));
},
defineProperty: function defineProperty(target, p, attributes) {
var from = descriptorTargetMap.get(p);
/*
Descriptor must be defined to native window while it comes from native window via Object.getOwnPropertyDescriptor(window, p),
otherwise it would cause a TypeError with illegal invocation.
*/
switch (from) {
case 'globalContext':
return Reflect.defineProperty(globalContext, p, attributes);
default:
return Reflect.defineProperty(target, p, attributes);
}
},
deleteProperty: function deleteProperty(target, p) {
_this.registerRunningApp(name, proxy);
if (target.hasOwnProperty(p)) {
// @ts-ignore
delete target[p];
updatedValueSet.delete(p);
return true;
}
return true;
},
// makes sure `window instanceof Window` returns truthy in micro app
getPrototypeOf: function getPrototypeOf() {
return Reflect.getPrototypeOf(globalContext);
}
});
this.proxy = proxy;
activeSandboxCount++;
}
(0, _createClass2.default)(ProxySandbox, [{
key: "registerRunningApp",
value: function registerRunningApp(name, proxy) {
if (this.sandboxRunning) {
var currentRunningApp = (0, _common.getCurrentRunningApp)();
if (!currentRunningApp || currentRunningApp.name !== name) {
(0, _common.setCurrentRunningApp)({
name: name,
window: proxy
});
} // FIXME if you have any other good ideas
// remove the mark in next tick, thus we can identify whether it in micro app or not
// this approach is just a workaround, it could not cover all complex cases, such as the micro app runs in the same task context with master in some case
(0, _utils.nextTask)(function () {
(0, _common.setCurrentRunningApp)(null);
});
}
}
}, {
key: "active",
value: function active() {
if (!this.sandboxRunning) activeSandboxCount++;
this.sandboxRunning = true;
}
}, {
key: "inactive",
value: function inactive() {
var _this2 = this;
if (process.env.NODE_ENV === 'development') {
console.info("[qiankun:sandbox] ".concat(this.name, " modified global properties restore..."), (0, _toConsumableArray2.default)(this.updatedValueSet.keys()));
}
if (--activeSandboxCount === 0) {
variableWhiteList.forEach(function (p) {
if (_this2.proxy.hasOwnProperty(p)) {
// @ts-ignore
delete _this2.globalContext[p];
}
});
}
this.sandboxRunning = false;
}
}]);
return ProxySandbox;
}();
exports.default = ProxySandbox;