add internal getCurrentRunningApp api (#1697)

This commit is contained in:
Troy Li 2021-09-09 17:59:53 +08:00 committed by GitHub
parent b789e6c529
commit ad7feadd29
5 changed files with 44 additions and 27 deletions

View File

@ -396,7 +396,7 @@ A criterion for judging whether the business is closely related: <strong>Look at
- Usage
init global state, and return actions for communication. It is recommended to use in master, and slave get actions through props
init global state, and return actions for communication. It is recommended to use in master, and slave get actions through props.
- Return

View File

@ -4,7 +4,7 @@
*/
import { isBoundedFunction } from '../../utils';
import { getCurrentRunningSandboxProxy } from '../common';
import { getCurrentRunningApp } from '../common';
import ProxySandbox from '../proxySandbox';
declare global {
@ -234,17 +234,21 @@ test('document and eval accessing should modify the attachDocProxySymbol value e
const proxy4 = new ProxySandbox('eval-access-test2').proxy;
const d1 = proxy1.document;
expect(getCurrentRunningSandboxProxy()).toBe(proxy1);
expect(getCurrentRunningApp()?.window).toBe(proxy1);
expect(getCurrentRunningApp()?.name).toBe('doc-access-test1');
const d2 = proxy2.document;
expect(getCurrentRunningSandboxProxy()).toBe(proxy2);
expect(getCurrentRunningApp()?.window).toBe(proxy2);
expect(getCurrentRunningApp()?.name).toBe('doc-access-test2');
expect(d1).toBe(d2);
expect(d1).toBe(document);
const eval1 = proxy3.eval;
expect(getCurrentRunningSandboxProxy()).toBe(proxy3);
expect(getCurrentRunningApp()?.window).toBe(proxy3);
expect(getCurrentRunningApp()?.name).toBe('eval-access-test1');
const eval2 = proxy4.eval;
expect(getCurrentRunningSandboxProxy()).toBe(proxy4);
expect(getCurrentRunningApp()?.window).toBe(proxy4);
expect(getCurrentRunningApp()?.name).toBe('eval-access-test2');
expect(eval1).toBe(eval2);
// eslint-disable-next-line no-eval
@ -257,10 +261,11 @@ test('document attachDocProxySymbol mark should be remove before next task', (do
// @ts-ignore
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const d1 = proxy.document;
expect(getCurrentRunningSandboxProxy()).toBe(proxy);
expect(getCurrentRunningApp()?.window).toBe(proxy);
expect(getCurrentRunningApp()?.name).toBe('doc-symbol');
setTimeout(() => {
expect(getCurrentRunningSandboxProxy()).toBeNull();
expect(getCurrentRunningApp()).toBeNull();
done();
});
});
@ -357,11 +362,12 @@ it('should get current running sandbox proxy correctly', async () => {
const { proxy } = new ProxySandbox('running');
await Promise.resolve().then(() => {
expect(getCurrentRunningSandboxProxy()).toBeNull();
expect(getCurrentRunningApp()).toBeNull();
// @ts-ignore
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const unused = proxy.accessing;
expect(getCurrentRunningSandboxProxy()).toBe(proxy);
expect(getCurrentRunningApp()?.window).toBe(proxy);
expect(getCurrentRunningApp()?.name).toBe('running');
});
});

View File

@ -7,21 +7,26 @@ import { isBoundedFunction, isCallable, isConstructable } from '../utils';
declare global {
interface Window {
__currentRunningSandboxProxy__: WindowProxy | null;
__currentRunningAppInSandbox__: { name: string; window: WindowProxy } | null;
}
}
// Get native global window with a sandbox disgusted way, thus we could share it between qiankun instances🤪
// eslint-disable-next-line no-new-func
const nativeGlobal: Window = new Function('return this')();
Object.defineProperty(nativeGlobal, '__currentRunningSandboxProxy__', { enumerable: false, writable: true });
export function getCurrentRunningSandboxProxy() {
return nativeGlobal.__currentRunningSandboxProxy__;
Object.defineProperty(nativeGlobal, '__currentRunningAppInSandbox__', { enumerable: false, writable: true });
/**
* get the app that running tasks at current tick
* @warning this method only works with proxy sandbox, right now it is for internal use only.
*/
export function getCurrentRunningApp() {
return nativeGlobal.__currentRunningAppInSandbox__;
}
export function setCurrentRunningSandboxProxy(proxy: WindowProxy | null) {
// set currentRunningSandboxProxy to global window, as its only use case is for document.createElement from now on, which hijacked by a global way
nativeGlobal.__currentRunningSandboxProxy__ = proxy;
export function setCurrentRunningApp(instance: { name: string; window: WindowProxy } | null) {
// set currentRunningApp and it's proxySandbox to global window, as its only use case is for document.createElement from now on, which hijacked by a global way
nativeGlobal.__currentRunningAppInSandbox__ = instance;
}
const functionBoundedValueMap = new WeakMap<CallableFunction, CallableFunction>();

View File

@ -4,7 +4,7 @@
*/
import type { Freer } from '../../../interfaces';
import { getCurrentRunningSandboxProxy } from '../../common';
import { getCurrentRunningApp } from '../../common';
import type { ContainerConfig } from './common';
import {
isHijackingTag,
@ -27,7 +27,7 @@ function patchDocumentCreateElement() {
): HTMLElement {
const element = rawDocumentCreateElement.call(this, tagName, options);
if (isHijackingTag(tagName)) {
const currentRunningSandboxProxy = getCurrentRunningSandboxProxy();
const { window: currentRunningSandboxProxy } = getCurrentRunningApp() || {};
if (currentRunningSandboxProxy) {
const proxyContainerConfig = proxyAttachContainerConfigMap.get(currentRunningSandboxProxy);
if (proxyContainerConfig) {

View File

@ -6,7 +6,7 @@
import type { SandBox } from '../interfaces';
import { SandBoxType } from '../interfaces';
import { nextTask } from '../utils';
import { getTargetValue, setCurrentRunningSandboxProxy } from './common';
import { getTargetValue, setCurrentRunningApp } from './common';
/**
* fastest(at most time) unique array method
@ -122,6 +122,16 @@ function createFakeWindow(global: Window) {
let activeSandboxCount = 0;
function registerRunningApp(name: string, proxy: Window) {
setCurrentRunningApp({ 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
nextTask(() => {
setCurrentRunningApp(null);
});
}
/**
* Proxy
*/
@ -177,6 +187,7 @@ export default class ProxySandbox implements SandBox {
const proxy = new Proxy(fakeWindow, {
set: (target: FakeWindow, p: PropertyKey, value: any): boolean => {
if (this.sandboxRunning) {
registerRunningApp(name, proxy);
// We must kept its description while the property existed in rawWindow before
if (!target.hasOwnProperty(p) && rawWindow.hasOwnProperty(p)) {
const descriptor = Object.getOwnPropertyDescriptor(rawWindow, p);
@ -216,13 +227,7 @@ export default class ProxySandbox implements SandBox {
get(target: FakeWindow, p: PropertyKey): any {
if (p === Symbol.unscopables) return unscopables;
setCurrentRunningSandboxProxy(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
nextTask(() => setCurrentRunningSandboxProxy(null));
registerRunningApp(name, proxy);
// 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') {
@ -323,6 +328,7 @@ export default class ProxySandbox implements SandBox {
},
deleteProperty(target: FakeWindow, p: string | number | symbol): boolean {
registerRunningApp(name, proxy);
if (target.hasOwnProperty(p)) {
// @ts-ignore
delete target[p];