🐛not rebind non-native global properties (#2733)
This commit is contained in:
parent
aa4a75c5a6
commit
3524195989
|
|
@ -13,11 +13,14 @@ writeFileSync(
|
|||
globalsFilePath,
|
||||
`// generated from https://github.com/sindresorhus/globals/blob/main/globals.json es2015 part
|
||||
// only init its values while Proxy is supported
|
||||
export const globals = window.Proxy ? ${JSON.stringify(
|
||||
export const globalsInES2015 = window.Proxy ? ${JSON.stringify(
|
||||
Object.keys(globals.es2015),
|
||||
null,
|
||||
2,
|
||||
)}.filter(p => /* just keep the available properties in current window context */ p in window) : [];`,
|
||||
)}.filter(p => /* just keep the available properties in current window context */ p in window) : [];
|
||||
|
||||
export const globalsInBrowser = ${JSON.stringify(Object.keys(globals.browser), null, 2)};
|
||||
`,
|
||||
);
|
||||
|
||||
export default {
|
||||
|
|
|
|||
|
|
@ -3,17 +3,17 @@
|
|||
* @since 2021-04-12
|
||||
*/
|
||||
|
||||
import { getTargetValue } from '../common';
|
||||
import { rebindTarget2Fn } from '../common';
|
||||
|
||||
describe('getTargetValue', () => {
|
||||
it('should work well', () => {
|
||||
const a1 = getTargetValue(window, undefined);
|
||||
const a1 = rebindTarget2Fn(window, undefined);
|
||||
expect(a1).toEqual(undefined);
|
||||
|
||||
const a2 = getTargetValue(window, null);
|
||||
const a2 = rebindTarget2Fn(window, null);
|
||||
expect(a2).toEqual(null);
|
||||
|
||||
const a3 = getTargetValue(window, function bindThis(this: any) {
|
||||
const a3 = rebindTarget2Fn(window, function bindThis(this: any) {
|
||||
return this;
|
||||
});
|
||||
const a3returns = a3();
|
||||
|
|
@ -24,7 +24,7 @@ describe('getTargetValue', () => {
|
|||
function prototypeAddedAfterFirstInvocation(this: any, field: string) {
|
||||
this.field = field;
|
||||
}
|
||||
const notConstructableFunction = getTargetValue(window, prototypeAddedAfterFirstInvocation);
|
||||
const notConstructableFunction = rebindTarget2Fn(window, prototypeAddedAfterFirstInvocation);
|
||||
// `this` of not constructable function will be bound automatically, and it can not be changed by calling with special `this`
|
||||
const result = {};
|
||||
notConstructableFunction.call(result, '123');
|
||||
|
|
@ -32,7 +32,7 @@ describe('getTargetValue', () => {
|
|||
expect(window.field).toEqual('123');
|
||||
|
||||
prototypeAddedAfterFirstInvocation.prototype.addedFn = () => {};
|
||||
const constructableFunction = getTargetValue(window, prototypeAddedAfterFirstInvocation);
|
||||
const constructableFunction = rebindTarget2Fn(window, prototypeAddedAfterFirstInvocation);
|
||||
// `this` coule be available if it be predicated as a constructable function
|
||||
const result2 = {};
|
||||
constructableFunction.call(result2, '456');
|
||||
|
|
@ -40,7 +40,7 @@ describe('getTargetValue', () => {
|
|||
// window.field not be affected
|
||||
expect(window.field).toEqual('123');
|
||||
// reference should be stable after first running
|
||||
expect(constructableFunction).toBe(getTargetValue(window, prototypeAddedAfterFirstInvocation));
|
||||
expect(constructableFunction).toBe(rebindTarget2Fn(window, prototypeAddedAfterFirstInvocation));
|
||||
});
|
||||
|
||||
it('should work well while value have a readonly prototype on its prototype chain', () => {
|
||||
|
|
@ -56,7 +56,7 @@ describe('getTargetValue', () => {
|
|||
|
||||
Object.setPrototypeOf(callableFunction, functionWithReadonlyPrototype);
|
||||
|
||||
const boundFn = getTargetValue(window, callableFunction);
|
||||
const boundFn = rebindTarget2Fn(window, callableFunction);
|
||||
expect(boundFn.prototype).toBe(callableFunction.prototype);
|
||||
});
|
||||
|
||||
|
|
@ -71,9 +71,9 @@ describe('getTargetValue', () => {
|
|||
},
|
||||
});
|
||||
|
||||
const boundFn1 = getTargetValue(window, callableFunction1);
|
||||
const boundFn2 = getTargetValue(window, callableFunction2);
|
||||
const boundFn3 = getTargetValue(window, callableFunction3);
|
||||
const boundFn1 = rebindTarget2Fn(window, callableFunction1);
|
||||
const boundFn2 = rebindTarget2Fn(window, callableFunction2);
|
||||
const boundFn3 = rebindTarget2Fn(window, callableFunction3);
|
||||
|
||||
expect(boundFn1.toString()).toBe(callableFunction1.toString());
|
||||
expect(boundFn2.toString()).toBe(callableFunction2.toString());
|
||||
|
|
|
|||
|
|
@ -293,16 +293,35 @@ it('document should work well with MutationObserver', (done) => {
|
|||
docProxy.document.body.innerHTML = '<div></div>';
|
||||
});
|
||||
|
||||
it('bounded function should not be rebounded', () => {
|
||||
const proxy = new ProxySandbox('bound-fn-test').proxy as any;
|
||||
const fn = () => {};
|
||||
const boundedFn = fn.bind(null);
|
||||
proxy.fn1 = fn;
|
||||
proxy.fn2 = boundedFn;
|
||||
it('native window function calling should always be bound with window', () => {
|
||||
window.mockNativeWindowFunction = function mockNativeWindowFunction(this: any) {
|
||||
if (this !== undefined && this !== window) {
|
||||
throw new Error('Illegal Invocation!');
|
||||
}
|
||||
|
||||
expect(proxy.fn1 === fn).toBeFalsy();
|
||||
expect(proxy.fn2 === boundedFn).toBeTruthy();
|
||||
expect(isBoundedFunction(proxy.fn1)).toBeTruthy();
|
||||
return 'success';
|
||||
};
|
||||
|
||||
const { proxy } = new ProxySandbox('mustBeBoundWithWindowReference');
|
||||
expect(proxy.mockNativeWindowFunction()).toBe('success');
|
||||
});
|
||||
|
||||
it('native bounded function should not be rebounded', () => {
|
||||
const proxy = new ProxySandbox('bound-native-fn-test').proxy as any;
|
||||
const boundedFn = atob.bind(null);
|
||||
proxy.atob = boundedFn;
|
||||
|
||||
expect(proxy.atob === boundedFn).toBeTruthy();
|
||||
expect(isBoundedFunction(proxy.atob)).toBeTruthy();
|
||||
});
|
||||
|
||||
it('non-native function should not be rebounded', () => {
|
||||
const proxy = new ProxySandbox('non-native-fn-bound-test').proxy as any;
|
||||
function test() {}
|
||||
proxy.fn = test;
|
||||
|
||||
expect(proxy.fn === test).toBeTruthy();
|
||||
expect(isBoundedFunction(proxy.fn)).toBeFalsy();
|
||||
});
|
||||
|
||||
it('frozen property should not be overwrite', () => {
|
||||
|
|
@ -332,12 +351,8 @@ it('frozen property should not be overwrite', () => {
|
|||
|
||||
it('the prototype should be kept while we create a function with prototype on proxy', () => {
|
||||
const proxy = new ProxySandbox('new-function').proxy as any;
|
||||
|
||||
function test() {}
|
||||
|
||||
proxy.fn = test;
|
||||
expect(proxy.fn === test).toBeFalsy();
|
||||
expect(proxy.fn.prototype).toBe(test.prototype);
|
||||
proxy.CustomEvent = CustomEvent;
|
||||
expect(proxy.CustomEvent.prototype).toBe(CustomEvent.prototype);
|
||||
});
|
||||
|
||||
it('some native window property was defined with getter in safari and firefox, and they will check the caller source', () => {
|
||||
|
|
@ -399,19 +414,6 @@ it('should get current running sandbox proxy correctly', async () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('native window function calling should always be bound with window', () => {
|
||||
window.nativeWindowFunction = function nativeWindowFunction(this: any) {
|
||||
if (this !== undefined && this !== window) {
|
||||
throw new Error('Illegal Invocation!');
|
||||
}
|
||||
|
||||
return 'success';
|
||||
};
|
||||
|
||||
const { proxy } = new ProxySandbox('mustBeBoundWithWindowReference');
|
||||
expect(proxy.nativeWindowFunction()).toBe('success');
|
||||
});
|
||||
|
||||
describe('should work well while the property existed in global context before', () => {
|
||||
it('should not write value while the readonly property existed in global context but not in sandbox', () => {
|
||||
Object.defineProperty(window, 'readonlyPropertyInGlobalContext', {
|
||||
|
|
|
|||
|
|
@ -26,60 +26,60 @@ export function clearCurrentRunningApp() {
|
|||
|
||||
const functionBoundedValueMap = new WeakMap<CallableFunction, CallableFunction>();
|
||||
|
||||
export function getTargetValue(target: any, value: any): any {
|
||||
export function rebindTarget2Fn(target: any, fn: any): any {
|
||||
/*
|
||||
仅绑定 isCallable && !isBoundedFunction && !isConstructable 的函数对象,如 window.console、window.atob 这类,不然微应用中调用时会抛出 Illegal invocation 异常
|
||||
目前没有完美的检测方式,这里通过 prototype 中是否还有可枚举的拓展方法的方式来判断
|
||||
@warning 这里不要随意替换成别的判断方式,因为可能触发一些 edge case(比如在 lodash.isFunction 在 iframe 上下文中可能由于调用了 top window 对象触发的安全异常)
|
||||
*/
|
||||
if (isCallable(value) && !isBoundedFunction(value) && !isConstructable(value)) {
|
||||
const cachedBoundFunction = functionBoundedValueMap.get(value);
|
||||
if (isCallable(fn) && !isBoundedFunction(fn) && !isConstructable(fn)) {
|
||||
const cachedBoundFunction = functionBoundedValueMap.get(fn);
|
||||
if (cachedBoundFunction) {
|
||||
return cachedBoundFunction;
|
||||
}
|
||||
|
||||
const boundValue = Function.prototype.bind.call(value, target);
|
||||
const boundValue = Function.prototype.bind.call(fn, target);
|
||||
|
||||
// some callable function has custom fields, we need to copy the own props to boundValue. such as moment function.
|
||||
Object.getOwnPropertyNames(value).forEach((key) => {
|
||||
Object.getOwnPropertyNames(fn).forEach((key) => {
|
||||
// boundValue might be a proxy, we need to check the key whether exist in it
|
||||
if (!boundValue.hasOwnProperty(key)) {
|
||||
Object.defineProperty(boundValue, key, Object.getOwnPropertyDescriptor(value, key)!);
|
||||
Object.defineProperty(boundValue, key, Object.getOwnPropertyDescriptor(fn, key)!);
|
||||
}
|
||||
});
|
||||
|
||||
// copy prototype if bound function not have but target one have
|
||||
// as prototype is non-enumerable mostly, we need to copy it from target function manually
|
||||
if (value.hasOwnProperty('prototype') && !boundValue.hasOwnProperty('prototype')) {
|
||||
// we should not use assignment operator to set boundValue prototype like `boundValue.prototype = value.prototype`
|
||||
if (fn.hasOwnProperty('prototype') && !boundValue.hasOwnProperty('prototype')) {
|
||||
// we should not use assignment operator to set boundValue prototype like `boundValue.prototype = fn.prototype`
|
||||
// as the assignment will also look up prototype chain while it hasn't own prototype property,
|
||||
// when the lookup succeed, the assignment will throw an TypeError like `Cannot assign to read only property 'prototype' of function` if its descriptor configured with writable false or just have a getter accessor
|
||||
// see https://github.com/umijs/qiankun/issues/1121
|
||||
Object.defineProperty(boundValue, 'prototype', { value: value.prototype, enumerable: false, writable: true });
|
||||
Object.defineProperty(boundValue, 'prototype', { value: fn.prototype, enumerable: false, writable: true });
|
||||
}
|
||||
|
||||
// Some util, like `function isNative() { return typeof Ctor === 'function' && /native code/.test(Ctor.toString()) }` relies on the original `toString()` result
|
||||
// but bound functions will always return "function() {[native code]}" for `toString`, which is misleading
|
||||
if (typeof value.toString === 'function') {
|
||||
const valueHasInstanceToString = value.hasOwnProperty('toString') && !boundValue.hasOwnProperty('toString');
|
||||
if (typeof fn.toString === 'function') {
|
||||
const valueHasInstanceToString = fn.hasOwnProperty('toString') && !boundValue.hasOwnProperty('toString');
|
||||
const boundValueHasPrototypeToString = boundValue.toString === Function.prototype.toString;
|
||||
|
||||
if (valueHasInstanceToString || boundValueHasPrototypeToString) {
|
||||
const originToStringDescriptor = Object.getOwnPropertyDescriptor(
|
||||
valueHasInstanceToString ? value : Function.prototype,
|
||||
valueHasInstanceToString ? fn : Function.prototype,
|
||||
'toString',
|
||||
);
|
||||
|
||||
Object.defineProperty(boundValue, 'toString', {
|
||||
...originToStringDescriptor,
|
||||
...(originToStringDescriptor?.get ? null : { value: () => value.toString() }),
|
||||
...(originToStringDescriptor?.get ? null : { value: () => fn.toString() }),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
functionBoundedValueMap.set(value, boundValue);
|
||||
functionBoundedValueMap.set(fn, boundValue);
|
||||
return boundValue;
|
||||
}
|
||||
|
||||
return value;
|
||||
return fn;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// generated from https://github.com/sindresorhus/globals/blob/main/globals.json es2015 part
|
||||
// only init its values while Proxy is supported
|
||||
export const globals = window.Proxy
|
||||
export const globalsInES2015 = window.Proxy
|
||||
? [
|
||||
'Array',
|
||||
'ArrayBuffer',
|
||||
|
|
@ -61,3 +61,743 @@ export const globals = window.Proxy
|
|||
'WeakSet',
|
||||
].filter((p) => /* just keep the available properties in current window context */ p in window)
|
||||
: [];
|
||||
|
||||
export const globalsInBrowser = [
|
||||
'AbortController',
|
||||
'AbortSignal',
|
||||
'addEventListener',
|
||||
'alert',
|
||||
'AnalyserNode',
|
||||
'Animation',
|
||||
'AnimationEffectReadOnly',
|
||||
'AnimationEffectTiming',
|
||||
'AnimationEffectTimingReadOnly',
|
||||
'AnimationEvent',
|
||||
'AnimationPlaybackEvent',
|
||||
'AnimationTimeline',
|
||||
'applicationCache',
|
||||
'ApplicationCache',
|
||||
'ApplicationCacheErrorEvent',
|
||||
'atob',
|
||||
'Attr',
|
||||
'Audio',
|
||||
'AudioBuffer',
|
||||
'AudioBufferSourceNode',
|
||||
'AudioContext',
|
||||
'AudioDestinationNode',
|
||||
'AudioListener',
|
||||
'AudioNode',
|
||||
'AudioParam',
|
||||
'AudioProcessingEvent',
|
||||
'AudioScheduledSourceNode',
|
||||
'AudioWorkletGlobalScope',
|
||||
'AudioWorkletNode',
|
||||
'AudioWorkletProcessor',
|
||||
'BarProp',
|
||||
'BaseAudioContext',
|
||||
'BatteryManager',
|
||||
'BeforeUnloadEvent',
|
||||
'BiquadFilterNode',
|
||||
'Blob',
|
||||
'BlobEvent',
|
||||
'blur',
|
||||
'BroadcastChannel',
|
||||
'btoa',
|
||||
'BudgetService',
|
||||
'ByteLengthQueuingStrategy',
|
||||
'Cache',
|
||||
'caches',
|
||||
'CacheStorage',
|
||||
'cancelAnimationFrame',
|
||||
'cancelIdleCallback',
|
||||
'CanvasCaptureMediaStreamTrack',
|
||||
'CanvasGradient',
|
||||
'CanvasPattern',
|
||||
'CanvasRenderingContext2D',
|
||||
'ChannelMergerNode',
|
||||
'ChannelSplitterNode',
|
||||
'CharacterData',
|
||||
'clearInterval',
|
||||
'clearTimeout',
|
||||
'clientInformation',
|
||||
'ClipboardEvent',
|
||||
'ClipboardItem',
|
||||
'close',
|
||||
'closed',
|
||||
'CloseEvent',
|
||||
'Comment',
|
||||
'CompositionEvent',
|
||||
'CompressionStream',
|
||||
'confirm',
|
||||
'console',
|
||||
'ConstantSourceNode',
|
||||
'ConvolverNode',
|
||||
'CountQueuingStrategy',
|
||||
'createImageBitmap',
|
||||
'Credential',
|
||||
'CredentialsContainer',
|
||||
'crypto',
|
||||
'Crypto',
|
||||
'CryptoKey',
|
||||
'CSS',
|
||||
'CSSConditionRule',
|
||||
'CSSFontFaceRule',
|
||||
'CSSGroupingRule',
|
||||
'CSSImportRule',
|
||||
'CSSKeyframeRule',
|
||||
'CSSKeyframesRule',
|
||||
'CSSMatrixComponent',
|
||||
'CSSMediaRule',
|
||||
'CSSNamespaceRule',
|
||||
'CSSPageRule',
|
||||
'CSSPerspective',
|
||||
'CSSRotate',
|
||||
'CSSRule',
|
||||
'CSSRuleList',
|
||||
'CSSScale',
|
||||
'CSSSkew',
|
||||
'CSSSkewX',
|
||||
'CSSSkewY',
|
||||
'CSSStyleDeclaration',
|
||||
'CSSStyleRule',
|
||||
'CSSStyleSheet',
|
||||
'CSSSupportsRule',
|
||||
'CSSTransformValue',
|
||||
'CSSTranslate',
|
||||
'CustomElementRegistry',
|
||||
'customElements',
|
||||
'CustomEvent',
|
||||
'DataTransfer',
|
||||
'DataTransferItem',
|
||||
'DataTransferItemList',
|
||||
'DecompressionStream',
|
||||
'defaultstatus',
|
||||
'defaultStatus',
|
||||
'DelayNode',
|
||||
'DeviceMotionEvent',
|
||||
'DeviceOrientationEvent',
|
||||
'devicePixelRatio',
|
||||
'dispatchEvent',
|
||||
'document',
|
||||
'Document',
|
||||
'DocumentFragment',
|
||||
'DocumentType',
|
||||
'DOMError',
|
||||
'DOMException',
|
||||
'DOMImplementation',
|
||||
'DOMMatrix',
|
||||
'DOMMatrixReadOnly',
|
||||
'DOMParser',
|
||||
'DOMPoint',
|
||||
'DOMPointReadOnly',
|
||||
'DOMQuad',
|
||||
'DOMRect',
|
||||
'DOMRectList',
|
||||
'DOMRectReadOnly',
|
||||
'DOMStringList',
|
||||
'DOMStringMap',
|
||||
'DOMTokenList',
|
||||
'DragEvent',
|
||||
'DynamicsCompressorNode',
|
||||
'Element',
|
||||
'ErrorEvent',
|
||||
'event',
|
||||
'Event',
|
||||
'EventSource',
|
||||
'EventTarget',
|
||||
'external',
|
||||
'fetch',
|
||||
'File',
|
||||
'FileList',
|
||||
'FileReader',
|
||||
'find',
|
||||
'focus',
|
||||
'FocusEvent',
|
||||
'FontFace',
|
||||
'FontFaceSetLoadEvent',
|
||||
'FormData',
|
||||
'FormDataEvent',
|
||||
'frameElement',
|
||||
'frames',
|
||||
'GainNode',
|
||||
'Gamepad',
|
||||
'GamepadButton',
|
||||
'GamepadEvent',
|
||||
'getComputedStyle',
|
||||
'getSelection',
|
||||
'HashChangeEvent',
|
||||
'Headers',
|
||||
'history',
|
||||
'History',
|
||||
'HTMLAllCollection',
|
||||
'HTMLAnchorElement',
|
||||
'HTMLAreaElement',
|
||||
'HTMLAudioElement',
|
||||
'HTMLBaseElement',
|
||||
'HTMLBodyElement',
|
||||
'HTMLBRElement',
|
||||
'HTMLButtonElement',
|
||||
'HTMLCanvasElement',
|
||||
'HTMLCollection',
|
||||
'HTMLContentElement',
|
||||
'HTMLDataElement',
|
||||
'HTMLDataListElement',
|
||||
'HTMLDetailsElement',
|
||||
'HTMLDialogElement',
|
||||
'HTMLDirectoryElement',
|
||||
'HTMLDivElement',
|
||||
'HTMLDListElement',
|
||||
'HTMLDocument',
|
||||
'HTMLElement',
|
||||
'HTMLEmbedElement',
|
||||
'HTMLFieldSetElement',
|
||||
'HTMLFontElement',
|
||||
'HTMLFormControlsCollection',
|
||||
'HTMLFormElement',
|
||||
'HTMLFrameElement',
|
||||
'HTMLFrameSetElement',
|
||||
'HTMLHeadElement',
|
||||
'HTMLHeadingElement',
|
||||
'HTMLHRElement',
|
||||
'HTMLHtmlElement',
|
||||
'HTMLIFrameElement',
|
||||
'HTMLImageElement',
|
||||
'HTMLInputElement',
|
||||
'HTMLLabelElement',
|
||||
'HTMLLegendElement',
|
||||
'HTMLLIElement',
|
||||
'HTMLLinkElement',
|
||||
'HTMLMapElement',
|
||||
'HTMLMarqueeElement',
|
||||
'HTMLMediaElement',
|
||||
'HTMLMenuElement',
|
||||
'HTMLMetaElement',
|
||||
'HTMLMeterElement',
|
||||
'HTMLModElement',
|
||||
'HTMLObjectElement',
|
||||
'HTMLOListElement',
|
||||
'HTMLOptGroupElement',
|
||||
'HTMLOptionElement',
|
||||
'HTMLOptionsCollection',
|
||||
'HTMLOutputElement',
|
||||
'HTMLParagraphElement',
|
||||
'HTMLParamElement',
|
||||
'HTMLPictureElement',
|
||||
'HTMLPreElement',
|
||||
'HTMLProgressElement',
|
||||
'HTMLQuoteElement',
|
||||
'HTMLScriptElement',
|
||||
'HTMLSelectElement',
|
||||
'HTMLShadowElement',
|
||||
'HTMLSlotElement',
|
||||
'HTMLSourceElement',
|
||||
'HTMLSpanElement',
|
||||
'HTMLStyleElement',
|
||||
'HTMLTableCaptionElement',
|
||||
'HTMLTableCellElement',
|
||||
'HTMLTableColElement',
|
||||
'HTMLTableElement',
|
||||
'HTMLTableRowElement',
|
||||
'HTMLTableSectionElement',
|
||||
'HTMLTemplateElement',
|
||||
'HTMLTextAreaElement',
|
||||
'HTMLTimeElement',
|
||||
'HTMLTitleElement',
|
||||
'HTMLTrackElement',
|
||||
'HTMLUListElement',
|
||||
'HTMLUnknownElement',
|
||||
'HTMLVideoElement',
|
||||
'IDBCursor',
|
||||
'IDBCursorWithValue',
|
||||
'IDBDatabase',
|
||||
'IDBFactory',
|
||||
'IDBIndex',
|
||||
'IDBKeyRange',
|
||||
'IDBObjectStore',
|
||||
'IDBOpenDBRequest',
|
||||
'IDBRequest',
|
||||
'IDBTransaction',
|
||||
'IDBVersionChangeEvent',
|
||||
'IdleDeadline',
|
||||
'IIRFilterNode',
|
||||
'Image',
|
||||
'ImageBitmap',
|
||||
'ImageBitmapRenderingContext',
|
||||
'ImageCapture',
|
||||
'ImageData',
|
||||
'indexedDB',
|
||||
'innerHeight',
|
||||
'innerWidth',
|
||||
'InputEvent',
|
||||
'IntersectionObserver',
|
||||
'IntersectionObserverEntry',
|
||||
'Intl',
|
||||
'isSecureContext',
|
||||
'KeyboardEvent',
|
||||
'KeyframeEffect',
|
||||
'KeyframeEffectReadOnly',
|
||||
'length',
|
||||
'localStorage',
|
||||
'location',
|
||||
'Location',
|
||||
'locationbar',
|
||||
'matchMedia',
|
||||
'MediaDeviceInfo',
|
||||
'MediaDevices',
|
||||
'MediaElementAudioSourceNode',
|
||||
'MediaEncryptedEvent',
|
||||
'MediaError',
|
||||
'MediaKeyMessageEvent',
|
||||
'MediaKeySession',
|
||||
'MediaKeyStatusMap',
|
||||
'MediaKeySystemAccess',
|
||||
'MediaList',
|
||||
'MediaMetadata',
|
||||
'MediaQueryList',
|
||||
'MediaQueryListEvent',
|
||||
'MediaRecorder',
|
||||
'MediaSettingsRange',
|
||||
'MediaSource',
|
||||
'MediaStream',
|
||||
'MediaStreamAudioDestinationNode',
|
||||
'MediaStreamAudioSourceNode',
|
||||
'MediaStreamEvent',
|
||||
'MediaStreamTrack',
|
||||
'MediaStreamTrackEvent',
|
||||
'menubar',
|
||||
'MessageChannel',
|
||||
'MessageEvent',
|
||||
'MessagePort',
|
||||
'MIDIAccess',
|
||||
'MIDIConnectionEvent',
|
||||
'MIDIInput',
|
||||
'MIDIInputMap',
|
||||
'MIDIMessageEvent',
|
||||
'MIDIOutput',
|
||||
'MIDIOutputMap',
|
||||
'MIDIPort',
|
||||
'MimeType',
|
||||
'MimeTypeArray',
|
||||
'MouseEvent',
|
||||
'moveBy',
|
||||
'moveTo',
|
||||
'MutationEvent',
|
||||
'MutationObserver',
|
||||
'MutationRecord',
|
||||
'name',
|
||||
'NamedNodeMap',
|
||||
'NavigationPreloadManager',
|
||||
'navigator',
|
||||
'Navigator',
|
||||
'NavigatorUAData',
|
||||
'NetworkInformation',
|
||||
'Node',
|
||||
'NodeFilter',
|
||||
'NodeIterator',
|
||||
'NodeList',
|
||||
'Notification',
|
||||
'OfflineAudioCompletionEvent',
|
||||
'OfflineAudioContext',
|
||||
'offscreenBuffering',
|
||||
'OffscreenCanvas',
|
||||
'OffscreenCanvasRenderingContext2D',
|
||||
'onabort',
|
||||
'onafterprint',
|
||||
'onanimationend',
|
||||
'onanimationiteration',
|
||||
'onanimationstart',
|
||||
'onappinstalled',
|
||||
'onauxclick',
|
||||
'onbeforeinstallprompt',
|
||||
'onbeforeprint',
|
||||
'onbeforeunload',
|
||||
'onblur',
|
||||
'oncancel',
|
||||
'oncanplay',
|
||||
'oncanplaythrough',
|
||||
'onchange',
|
||||
'onclick',
|
||||
'onclose',
|
||||
'oncontextmenu',
|
||||
'oncuechange',
|
||||
'ondblclick',
|
||||
'ondevicemotion',
|
||||
'ondeviceorientation',
|
||||
'ondeviceorientationabsolute',
|
||||
'ondrag',
|
||||
'ondragend',
|
||||
'ondragenter',
|
||||
'ondragleave',
|
||||
'ondragover',
|
||||
'ondragstart',
|
||||
'ondrop',
|
||||
'ondurationchange',
|
||||
'onemptied',
|
||||
'onended',
|
||||
'onerror',
|
||||
'onfocus',
|
||||
'ongotpointercapture',
|
||||
'onhashchange',
|
||||
'oninput',
|
||||
'oninvalid',
|
||||
'onkeydown',
|
||||
'onkeypress',
|
||||
'onkeyup',
|
||||
'onlanguagechange',
|
||||
'onload',
|
||||
'onloadeddata',
|
||||
'onloadedmetadata',
|
||||
'onloadstart',
|
||||
'onlostpointercapture',
|
||||
'onmessage',
|
||||
'onmessageerror',
|
||||
'onmousedown',
|
||||
'onmouseenter',
|
||||
'onmouseleave',
|
||||
'onmousemove',
|
||||
'onmouseout',
|
||||
'onmouseover',
|
||||
'onmouseup',
|
||||
'onmousewheel',
|
||||
'onoffline',
|
||||
'ononline',
|
||||
'onpagehide',
|
||||
'onpageshow',
|
||||
'onpause',
|
||||
'onplay',
|
||||
'onplaying',
|
||||
'onpointercancel',
|
||||
'onpointerdown',
|
||||
'onpointerenter',
|
||||
'onpointerleave',
|
||||
'onpointermove',
|
||||
'onpointerout',
|
||||
'onpointerover',
|
||||
'onpointerup',
|
||||
'onpopstate',
|
||||
'onprogress',
|
||||
'onratechange',
|
||||
'onrejectionhandled',
|
||||
'onreset',
|
||||
'onresize',
|
||||
'onscroll',
|
||||
'onsearch',
|
||||
'onseeked',
|
||||
'onseeking',
|
||||
'onselect',
|
||||
'onstalled',
|
||||
'onstorage',
|
||||
'onsubmit',
|
||||
'onsuspend',
|
||||
'ontimeupdate',
|
||||
'ontoggle',
|
||||
'ontransitionend',
|
||||
'onunhandledrejection',
|
||||
'onunload',
|
||||
'onvolumechange',
|
||||
'onwaiting',
|
||||
'onwheel',
|
||||
'open',
|
||||
'openDatabase',
|
||||
'opener',
|
||||
'Option',
|
||||
'origin',
|
||||
'OscillatorNode',
|
||||
'outerHeight',
|
||||
'outerWidth',
|
||||
'OverconstrainedError',
|
||||
'PageTransitionEvent',
|
||||
'pageXOffset',
|
||||
'pageYOffset',
|
||||
'PannerNode',
|
||||
'parent',
|
||||
'Path2D',
|
||||
'PaymentAddress',
|
||||
'PaymentRequest',
|
||||
'PaymentRequestUpdateEvent',
|
||||
'PaymentResponse',
|
||||
'performance',
|
||||
'Performance',
|
||||
'PerformanceEntry',
|
||||
'PerformanceLongTaskTiming',
|
||||
'PerformanceMark',
|
||||
'PerformanceMeasure',
|
||||
'PerformanceNavigation',
|
||||
'PerformanceNavigationTiming',
|
||||
'PerformanceObserver',
|
||||
'PerformanceObserverEntryList',
|
||||
'PerformancePaintTiming',
|
||||
'PerformanceResourceTiming',
|
||||
'PerformanceTiming',
|
||||
'PeriodicWave',
|
||||
'Permissions',
|
||||
'PermissionStatus',
|
||||
'personalbar',
|
||||
'PhotoCapabilities',
|
||||
'Plugin',
|
||||
'PluginArray',
|
||||
'PointerEvent',
|
||||
'PopStateEvent',
|
||||
'postMessage',
|
||||
'Presentation',
|
||||
'PresentationAvailability',
|
||||
'PresentationConnection',
|
||||
'PresentationConnectionAvailableEvent',
|
||||
'PresentationConnectionCloseEvent',
|
||||
'PresentationConnectionList',
|
||||
'PresentationReceiver',
|
||||
'PresentationRequest',
|
||||
'print',
|
||||
'ProcessingInstruction',
|
||||
'ProgressEvent',
|
||||
'PromiseRejectionEvent',
|
||||
'prompt',
|
||||
'PushManager',
|
||||
'PushSubscription',
|
||||
'PushSubscriptionOptions',
|
||||
'queueMicrotask',
|
||||
'RadioNodeList',
|
||||
'Range',
|
||||
'ReadableByteStreamController',
|
||||
'ReadableStream',
|
||||
'ReadableStreamBYOBReader',
|
||||
'ReadableStreamBYOBRequest',
|
||||
'ReadableStreamDefaultController',
|
||||
'ReadableStreamDefaultReader',
|
||||
'registerProcessor',
|
||||
'RemotePlayback',
|
||||
'removeEventListener',
|
||||
'reportError',
|
||||
'Request',
|
||||
'requestAnimationFrame',
|
||||
'requestIdleCallback',
|
||||
'resizeBy',
|
||||
'ResizeObserver',
|
||||
'ResizeObserverEntry',
|
||||
'resizeTo',
|
||||
'Response',
|
||||
'RTCCertificate',
|
||||
'RTCDataChannel',
|
||||
'RTCDataChannelEvent',
|
||||
'RTCDtlsTransport',
|
||||
'RTCIceCandidate',
|
||||
'RTCIceGatherer',
|
||||
'RTCIceTransport',
|
||||
'RTCPeerConnection',
|
||||
'RTCPeerConnectionIceEvent',
|
||||
'RTCRtpContributingSource',
|
||||
'RTCRtpReceiver',
|
||||
'RTCRtpSender',
|
||||
'RTCSctpTransport',
|
||||
'RTCSessionDescription',
|
||||
'RTCStatsReport',
|
||||
'RTCTrackEvent',
|
||||
'screen',
|
||||
'Screen',
|
||||
'screenLeft',
|
||||
'ScreenOrientation',
|
||||
'screenTop',
|
||||
'screenX',
|
||||
'screenY',
|
||||
'ScriptProcessorNode',
|
||||
'scroll',
|
||||
'scrollbars',
|
||||
'scrollBy',
|
||||
'scrollTo',
|
||||
'scrollX',
|
||||
'scrollY',
|
||||
'SecurityPolicyViolationEvent',
|
||||
'Selection',
|
||||
'self',
|
||||
'ServiceWorker',
|
||||
'ServiceWorkerContainer',
|
||||
'ServiceWorkerRegistration',
|
||||
'sessionStorage',
|
||||
'setInterval',
|
||||
'setTimeout',
|
||||
'ShadowRoot',
|
||||
'SharedWorker',
|
||||
'SourceBuffer',
|
||||
'SourceBufferList',
|
||||
'speechSynthesis',
|
||||
'SpeechSynthesisEvent',
|
||||
'SpeechSynthesisUtterance',
|
||||
'StaticRange',
|
||||
'status',
|
||||
'statusbar',
|
||||
'StereoPannerNode',
|
||||
'stop',
|
||||
'Storage',
|
||||
'StorageEvent',
|
||||
'StorageManager',
|
||||
'structuredClone',
|
||||
'styleMedia',
|
||||
'StyleSheet',
|
||||
'StyleSheetList',
|
||||
'SubmitEvent',
|
||||
'SubtleCrypto',
|
||||
'SVGAElement',
|
||||
'SVGAngle',
|
||||
'SVGAnimatedAngle',
|
||||
'SVGAnimatedBoolean',
|
||||
'SVGAnimatedEnumeration',
|
||||
'SVGAnimatedInteger',
|
||||
'SVGAnimatedLength',
|
||||
'SVGAnimatedLengthList',
|
||||
'SVGAnimatedNumber',
|
||||
'SVGAnimatedNumberList',
|
||||
'SVGAnimatedPreserveAspectRatio',
|
||||
'SVGAnimatedRect',
|
||||
'SVGAnimatedString',
|
||||
'SVGAnimatedTransformList',
|
||||
'SVGAnimateElement',
|
||||
'SVGAnimateMotionElement',
|
||||
'SVGAnimateTransformElement',
|
||||
'SVGAnimationElement',
|
||||
'SVGCircleElement',
|
||||
'SVGClipPathElement',
|
||||
'SVGComponentTransferFunctionElement',
|
||||
'SVGDefsElement',
|
||||
'SVGDescElement',
|
||||
'SVGDiscardElement',
|
||||
'SVGElement',
|
||||
'SVGEllipseElement',
|
||||
'SVGFEBlendElement',
|
||||
'SVGFEColorMatrixElement',
|
||||
'SVGFEComponentTransferElement',
|
||||
'SVGFECompositeElement',
|
||||
'SVGFEConvolveMatrixElement',
|
||||
'SVGFEDiffuseLightingElement',
|
||||
'SVGFEDisplacementMapElement',
|
||||
'SVGFEDistantLightElement',
|
||||
'SVGFEDropShadowElement',
|
||||
'SVGFEFloodElement',
|
||||
'SVGFEFuncAElement',
|
||||
'SVGFEFuncBElement',
|
||||
'SVGFEFuncGElement',
|
||||
'SVGFEFuncRElement',
|
||||
'SVGFEGaussianBlurElement',
|
||||
'SVGFEImageElement',
|
||||
'SVGFEMergeElement',
|
||||
'SVGFEMergeNodeElement',
|
||||
'SVGFEMorphologyElement',
|
||||
'SVGFEOffsetElement',
|
||||
'SVGFEPointLightElement',
|
||||
'SVGFESpecularLightingElement',
|
||||
'SVGFESpotLightElement',
|
||||
'SVGFETileElement',
|
||||
'SVGFETurbulenceElement',
|
||||
'SVGFilterElement',
|
||||
'SVGForeignObjectElement',
|
||||
'SVGGElement',
|
||||
'SVGGeometryElement',
|
||||
'SVGGradientElement',
|
||||
'SVGGraphicsElement',
|
||||
'SVGImageElement',
|
||||
'SVGLength',
|
||||
'SVGLengthList',
|
||||
'SVGLinearGradientElement',
|
||||
'SVGLineElement',
|
||||
'SVGMarkerElement',
|
||||
'SVGMaskElement',
|
||||
'SVGMatrix',
|
||||
'SVGMetadataElement',
|
||||
'SVGMPathElement',
|
||||
'SVGNumber',
|
||||
'SVGNumberList',
|
||||
'SVGPathElement',
|
||||
'SVGPatternElement',
|
||||
'SVGPoint',
|
||||
'SVGPointList',
|
||||
'SVGPolygonElement',
|
||||
'SVGPolylineElement',
|
||||
'SVGPreserveAspectRatio',
|
||||
'SVGRadialGradientElement',
|
||||
'SVGRect',
|
||||
'SVGRectElement',
|
||||
'SVGScriptElement',
|
||||
'SVGSetElement',
|
||||
'SVGStopElement',
|
||||
'SVGStringList',
|
||||
'SVGStyleElement',
|
||||
'SVGSVGElement',
|
||||
'SVGSwitchElement',
|
||||
'SVGSymbolElement',
|
||||
'SVGTextContentElement',
|
||||
'SVGTextElement',
|
||||
'SVGTextPathElement',
|
||||
'SVGTextPositioningElement',
|
||||
'SVGTitleElement',
|
||||
'SVGTransform',
|
||||
'SVGTransformList',
|
||||
'SVGTSpanElement',
|
||||
'SVGUnitTypes',
|
||||
'SVGUseElement',
|
||||
'SVGViewElement',
|
||||
'TaskAttributionTiming',
|
||||
'Text',
|
||||
'TextDecoder',
|
||||
'TextDecoderStream',
|
||||
'TextEncoder',
|
||||
'TextEncoderStream',
|
||||
'TextEvent',
|
||||
'TextMetrics',
|
||||
'TextTrack',
|
||||
'TextTrackCue',
|
||||
'TextTrackCueList',
|
||||
'TextTrackList',
|
||||
'TimeRanges',
|
||||
'toolbar',
|
||||
'top',
|
||||
'Touch',
|
||||
'TouchEvent',
|
||||
'TouchList',
|
||||
'TrackEvent',
|
||||
'TransformStream',
|
||||
'TransformStreamDefaultController',
|
||||
'TransitionEvent',
|
||||
'TreeWalker',
|
||||
'UIEvent',
|
||||
'URL',
|
||||
'URLSearchParams',
|
||||
'ValidityState',
|
||||
'visualViewport',
|
||||
'VisualViewport',
|
||||
'VTTCue',
|
||||
'WaveShaperNode',
|
||||
'WebAssembly',
|
||||
'WebGL2RenderingContext',
|
||||
'WebGLActiveInfo',
|
||||
'WebGLBuffer',
|
||||
'WebGLContextEvent',
|
||||
'WebGLFramebuffer',
|
||||
'WebGLProgram',
|
||||
'WebGLQuery',
|
||||
'WebGLRenderbuffer',
|
||||
'WebGLRenderingContext',
|
||||
'WebGLSampler',
|
||||
'WebGLShader',
|
||||
'WebGLShaderPrecisionFormat',
|
||||
'WebGLSync',
|
||||
'WebGLTexture',
|
||||
'WebGLTransformFeedback',
|
||||
'WebGLUniformLocation',
|
||||
'WebGLVertexArrayObject',
|
||||
'WebSocket',
|
||||
'WheelEvent',
|
||||
'window',
|
||||
'Window',
|
||||
'Worker',
|
||||
'WritableStream',
|
||||
'WritableStreamDefaultController',
|
||||
'WritableStreamDefaultWriter',
|
||||
'XMLDocument',
|
||||
'XMLHttpRequest',
|
||||
'XMLHttpRequestEventTarget',
|
||||
'XMLHttpRequestUpload',
|
||||
'XMLSerializer',
|
||||
'XPathEvaluator',
|
||||
'XPathExpression',
|
||||
'XPathResult',
|
||||
'XSLTProcessor',
|
||||
];
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
*/
|
||||
import type { SandBox } from '../../interfaces';
|
||||
import { SandBoxType } from '../../interfaces';
|
||||
import { getTargetValue } from '../common';
|
||||
import { rebindTarget2Fn } from '../common';
|
||||
|
||||
function isPropConfigurable(target: WindowProxy, prop: PropertyKey) {
|
||||
const descriptor = Object.getOwnPropertyDescriptor(target, prop);
|
||||
|
|
@ -125,7 +125,7 @@ export default class LegacySandbox implements SandBox {
|
|||
}
|
||||
|
||||
const value = (rawWindow as any)[p];
|
||||
return getTargetValue(rawWindow, value);
|
||||
return rebindTarget2Fn(rawWindow, value);
|
||||
},
|
||||
|
||||
// trap in operator
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
/* eslint-disable no-param-reassign */
|
||||
import { without } from 'lodash';
|
||||
/**
|
||||
* @author Kuitos
|
||||
* @since 2020-3-31
|
||||
*/
|
||||
import { without } from 'lodash';
|
||||
import type { SandBox } from '../interfaces';
|
||||
import { SandBoxType } from '../interfaces';
|
||||
import { isPropertyFrozen, nativeGlobal, nextTask } from '../utils';
|
||||
import { clearCurrentRunningApp, getCurrentRunningApp, getTargetValue, setCurrentRunningApp } from './common';
|
||||
import { globals } from './globals';
|
||||
import { clearCurrentRunningApp, getCurrentRunningApp, rebindTarget2Fn, setCurrentRunningApp } from './common';
|
||||
import { globalsInBrowser, globalsInES2015 } from './globals';
|
||||
|
||||
type SymbolTarget = 'target' | 'globalContext';
|
||||
|
||||
|
|
@ -24,6 +24,13 @@ function uniq(array: Array<string | symbol>) {
|
|||
}, Object.create(null));
|
||||
}
|
||||
|
||||
const cachedGlobalsInBrowser = globalsInBrowser
|
||||
.concat(process.env.NODE_ENV === 'test' ? ['mockNativeWindowFunction'] : [])
|
||||
.reduce<Record<string, true>>((acc, key) => ({ ...acc, [key]: true }), Object.create(null));
|
||||
function isNativeGlobalProp(prop: string): boolean {
|
||||
return prop in cachedGlobalsInBrowser;
|
||||
}
|
||||
|
||||
// zone.js will overwrite Object.defineProperty
|
||||
const rawObjectDefineProperty = Object.defineProperty;
|
||||
|
||||
|
|
@ -58,7 +65,9 @@ const mockGlobalThis = 'mockGlobalThis';
|
|||
const accessingSpiedGlobals = ['document', 'top', 'parent', 'eval'];
|
||||
const overwrittenGlobals = ['window', 'self', 'globalThis', 'hasOwnProperty'].concat(inTest ? [mockGlobalThis] : []);
|
||||
export const cachedGlobals = Array.from(
|
||||
new Set(without(globals.concat(overwrittenGlobals).concat('requestAnimationFrame'), ...accessingSpiedGlobals)),
|
||||
new Set(
|
||||
without(globalsInES2015.concat(overwrittenGlobals).concat('requestAnimationFrame'), ...accessingSpiedGlobals),
|
||||
),
|
||||
);
|
||||
|
||||
// transform cachedGlobals to object for faster element check
|
||||
|
|
@ -297,14 +306,20 @@ export default class ProxySandbox implements SandBox {
|
|||
return value;
|
||||
}
|
||||
|
||||
// non-native property return directly to avoid rebind
|
||||
if (!isNativeGlobalProp(p as string) && !useNativeWindowForBindingsProps.has(p)) {
|
||||
return value;
|
||||
}
|
||||
|
||||
/* 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, {});
|
||||
// in nest sandbox fetch will be bind to proxy rather than window in master
|
||||
const proxyFetch = fetch.bind(proxy);
|
||||
proxyFetch('https://qiankun.com');
|
||||
*/
|
||||
const boundTarget = useNativeWindowForBindingsProps.get(p) ? nativeGlobal : globalContext;
|
||||
return getTargetValue(boundTarget, value);
|
||||
return rebindTarget2Fn(boundTarget, value);
|
||||
},
|
||||
|
||||
// trap in operator
|
||||
|
|
|
|||
|
|
@ -2,8 +2,7 @@
|
|||
* @author Kuitos
|
||||
* @since 2019-05-15
|
||||
*/
|
||||
|
||||
import { isFunction, once, snakeCase, memoize } from 'lodash';
|
||||
import { isFunction, memoize, once, snakeCase } from 'lodash';
|
||||
import type { FrameworkConfiguration } from './interfaces';
|
||||
import { version } from './version';
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user