diff --git a/.fatherrc.js b/.fatherrc.js
index 7f53b17..d7c4631 100644
--- a/.fatherrc.js
+++ b/.fatherrc.js
@@ -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 {
diff --git a/src/sandbox/__tests__/common.test.ts b/src/sandbox/__tests__/common.test.ts
index 429e21e..6a105f4 100644
--- a/src/sandbox/__tests__/common.test.ts
+++ b/src/sandbox/__tests__/common.test.ts
@@ -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());
diff --git a/src/sandbox/__tests__/proxySandbox.test.ts b/src/sandbox/__tests__/proxySandbox.test.ts
index 3cd52f2..ac29820 100644
--- a/src/sandbox/__tests__/proxySandbox.test.ts
+++ b/src/sandbox/__tests__/proxySandbox.test.ts
@@ -293,16 +293,35 @@ it('document should work well with MutationObserver', (done) => {
docProxy.document.body.innerHTML = '
';
});
-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', {
diff --git a/src/sandbox/common.ts b/src/sandbox/common.ts
index 83530fc..ff60bff 100644
--- a/src/sandbox/common.ts
+++ b/src/sandbox/common.ts
@@ -26,60 +26,60 @@ export function clearCurrentRunningApp() {
const functionBoundedValueMap = new WeakMap();
-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;
}
diff --git a/src/sandbox/globals.ts b/src/sandbox/globals.ts
index b0454e7..8eb828e 100644
--- a/src/sandbox/globals.ts
+++ b/src/sandbox/globals.ts
@@ -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',
+];
diff --git a/src/sandbox/legacy/sandbox.ts b/src/sandbox/legacy/sandbox.ts
index 98aea1a..4ab298e 100644
--- a/src/sandbox/legacy/sandbox.ts
+++ b/src/sandbox/legacy/sandbox.ts
@@ -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
diff --git a/src/sandbox/proxySandbox.ts b/src/sandbox/proxySandbox.ts
index e69f7a6..9b81cc2 100644
--- a/src/sandbox/proxySandbox.ts
+++ b/src/sandbox/proxySandbox.ts
@@ -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) {
}, Object.create(null));
}
+const cachedGlobalsInBrowser = globalsInBrowser
+ .concat(process.env.NODE_ENV === 'test' ? ['mockNativeWindowFunction'] : [])
+ .reduce>((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
diff --git a/src/utils.ts b/src/utils.ts
index 88e312c..299cf30 100644
--- a/src/utils.ts
+++ b/src/utils.ts
@@ -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';