✨ remove global way for recording current running sandbox to fix nested scenario (#1723)
* ✨ remove global way for recording current running sandbox to support parallel multiple instance *✨ export internal getCurrentRunningApp API Co-authored-by: tli4 <a@tianyi.li>
This commit is contained in:
parent
91a238875b
commit
c4b604228a
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
export { loadMicroApp, registerMicroApps, start } from './apis';
|
||||
export { initGlobalState } from './globalState';
|
||||
export { getCurrentRunningApp as __internalGetCurrentRunningApp } from './sandbox';
|
||||
export * from './errorHandler';
|
||||
export * from './effects';
|
||||
export * from './interfaces';
|
||||
|
|
|
|||
|
|
@ -5,28 +5,18 @@
|
|||
|
||||
import { isBoundedFunction, isCallable, isConstructable } from '../utils';
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
__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, '__currentRunningAppInSandbox__', { enumerable: false, writable: true });
|
||||
|
||||
type AppInstance = { name: string; window: WindowProxy };
|
||||
let currentRunningApp: AppInstance | null = null;
|
||||
/**
|
||||
* 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__;
|
||||
return currentRunningApp;
|
||||
}
|
||||
|
||||
export function setCurrentRunningApp(instance: { name: string; window: WindowProxy } | null) {
|
||||
export function setCurrentRunningApp(appInstance: { 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;
|
||||
currentRunningApp = appInstance;
|
||||
}
|
||||
|
||||
const functionBoundedValueMap = new WeakMap<CallableFunction, CallableFunction>();
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import ProxySandbox from './proxySandbox';
|
|||
import SnapshotSandbox from './snapshotSandbox';
|
||||
|
||||
export { css } from './patchers';
|
||||
export { getCurrentRunningApp } from './common';
|
||||
|
||||
/**
|
||||
* 生成应用运行时沙箱
|
||||
|
|
|
|||
|
|
@ -14,10 +14,25 @@ import {
|
|||
recordStyledComponentsCSSRules,
|
||||
} from './common';
|
||||
|
||||
const rawDocumentCreateElement = Document.prototype.createElement;
|
||||
const proxyAttachContainerConfigMap = new WeakMap<WindowProxy, ContainerConfig>();
|
||||
declare global {
|
||||
interface Window {
|
||||
__proxyAttachContainerConfigMap__: WeakMap<WindowProxy, ContainerConfig>;
|
||||
}
|
||||
}
|
||||
|
||||
// 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, '__proxyAttachContainerConfigMap__', { enumerable: false, writable: true });
|
||||
|
||||
// Share proxyAttachContainerConfigMap between multiple qiankun instance, thus they could access the same record
|
||||
nativeGlobal.__proxyAttachContainerConfigMap__ =
|
||||
nativeGlobal.__proxyAttachContainerConfigMap__ || new WeakMap<WindowProxy, ContainerConfig>();
|
||||
const proxyAttachContainerConfigMap = nativeGlobal.__proxyAttachContainerConfigMap__;
|
||||
|
||||
const elementAttachContainerConfigMap = new WeakMap<HTMLElement, ContainerConfig>();
|
||||
|
||||
const rawDocumentCreateElement = Document.prototype.createElement;
|
||||
function patchDocumentCreateElement() {
|
||||
if (Document.prototype.createElement === rawDocumentCreateElement) {
|
||||
Document.prototype.createElement = function createElement<K extends keyof HTMLElementTagNameMap>(
|
||||
|
|
|
|||
|
|
@ -122,16 +122,6 @@ 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 实现的沙箱
|
||||
*/
|
||||
|
|
@ -151,6 +141,18 @@ export default class ProxySandbox implements SandBox {
|
|||
|
||||
latestSetProp: PropertyKey | null = null;
|
||||
|
||||
private registerRunningApp(name: string, proxy: Window) {
|
||||
if (this.sandboxRunning) {
|
||||
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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
active() {
|
||||
if (!this.sandboxRunning) activeSandboxCount++;
|
||||
this.sandboxRunning = true;
|
||||
|
|
@ -190,7 +192,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);
|
||||
this.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);
|
||||
|
|
@ -228,9 +230,10 @@ export default class ProxySandbox implements SandBox {
|
|||
return true;
|
||||
},
|
||||
|
||||
get(target: FakeWindow, p: PropertyKey): any {
|
||||
get: (target: FakeWindow, p: PropertyKey): any => {
|
||||
this.registerRunningApp(name, proxy);
|
||||
|
||||
if (p === Symbol.unscopables) return unscopables;
|
||||
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') {
|
||||
|
|
@ -330,8 +333,8 @@ export default class ProxySandbox implements SandBox {
|
|||
}
|
||||
},
|
||||
|
||||
deleteProperty(target: FakeWindow, p: string | number | symbol): boolean {
|
||||
registerRunningApp(name, proxy);
|
||||
deleteProperty: (target: FakeWindow, p: string | number | symbol): boolean => {
|
||||
this.registerRunningApp(name, proxy);
|
||||
if (target.hasOwnProperty(p)) {
|
||||
// @ts-ignore
|
||||
delete target[p];
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user