From c4b604228a2855bc5f68e0be33e2ca71b6188d3c Mon Sep 17 00:00:00 2001 From: Kuitos Date: Wed, 15 Sep 2021 22:54:44 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20remove=20global=20way=20for=20recor?= =?UTF-8?q?ding=20current=20running=20sandbox=20to=20fix=20nested=20scenar?= =?UTF-8?q?io=20(#1723)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ✨ remove global way for recording current running sandbox to support parallel multiple instance *✨ export internal getCurrentRunningApp API Co-authored-by: tli4 --- src/index.ts | 1 + src/sandbox/common.ts | 20 +++-------- src/sandbox/index.ts | 1 + .../dynamicAppend/forStrictSandbox.ts | 19 +++++++++-- src/sandbox/proxySandbox.ts | 33 ++++++++++--------- 5 files changed, 42 insertions(+), 32 deletions(-) diff --git a/src/index.ts b/src/index.ts index 87dbc77..4e05fe3 100644 --- a/src/index.ts +++ b/src/index.ts @@ -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'; diff --git a/src/sandbox/common.ts b/src/sandbox/common.ts index 36ef7b8..ebe3366 100644 --- a/src/sandbox/common.ts +++ b/src/sandbox/common.ts @@ -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(); diff --git a/src/sandbox/index.ts b/src/sandbox/index.ts index bc7f62e..9f983a6 100644 --- a/src/sandbox/index.ts +++ b/src/sandbox/index.ts @@ -9,6 +9,7 @@ import ProxySandbox from './proxySandbox'; import SnapshotSandbox from './snapshotSandbox'; export { css } from './patchers'; +export { getCurrentRunningApp } from './common'; /** * 生成应用运行时沙箱 diff --git a/src/sandbox/patchers/dynamicAppend/forStrictSandbox.ts b/src/sandbox/patchers/dynamicAppend/forStrictSandbox.ts index ab4ee4e..fdb930f 100644 --- a/src/sandbox/patchers/dynamicAppend/forStrictSandbox.ts +++ b/src/sandbox/patchers/dynamicAppend/forStrictSandbox.ts @@ -14,10 +14,25 @@ import { recordStyledComponentsCSSRules, } from './common'; -const rawDocumentCreateElement = Document.prototype.createElement; -const proxyAttachContainerConfigMap = new WeakMap(); +declare global { + interface Window { + __proxyAttachContainerConfigMap__: WeakMap; + } +} + +// 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(); +const proxyAttachContainerConfigMap = nativeGlobal.__proxyAttachContainerConfigMap__; const elementAttachContainerConfigMap = new WeakMap(); + +const rawDocumentCreateElement = Document.prototype.createElement; function patchDocumentCreateElement() { if (Document.prototype.createElement === rawDocumentCreateElement) { Document.prototype.createElement = function createElement( diff --git a/src/sandbox/proxySandbox.ts b/src/sandbox/proxySandbox.ts index 7a58a12..57e9c6d 100644 --- a/src/sandbox/proxySandbox.ts +++ b/src/sandbox/proxySandbox.ts @@ -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];