diff --git a/packages/qiankun/src/apis/loadMicroApp.ts b/packages/qiankun/src/apis/loadMicroApp.ts index 629a7fda9..26b075258 100644 --- a/packages/qiankun/src/apis/loadMicroApp.ts +++ b/packages/qiankun/src/apis/loadMicroApp.ts @@ -72,7 +72,7 @@ export function loadMicroApp( const parcelConfigObjectGetterPromise = loadApp(app, userConfiguration, lifeCycles); if (containerXPath) { - const appContainerXPathKey = `${name}-${containerXPath}`; + const appContainerXPathKey = getContainerXPathKey(containerXPath); appConfigPromiseGetterMap.set(appContainerXPathKey, parcelConfigObjectGetterPromise); } diff --git a/packages/qiankun/src/apis/registerMicroApps.ts b/packages/qiankun/src/apis/registerMicroApps.ts index 3937a9398..e2ca2184d 100644 --- a/packages/qiankun/src/apis/registerMicroApps.ts +++ b/packages/qiankun/src/apis/registerMicroApps.ts @@ -8,7 +8,7 @@ import { toArray } from '../utils'; export let started = false; -let microApps: Array>> = []; +export const microApps: Array>> = []; const frameworkConfiguration: AppConfiguration = {}; const frameworkStartedDefer = new Deferred(); @@ -17,7 +17,7 @@ export function registerMicroApps(apps: Array !microApps.some((registeredApp) => registeredApp.name === app.name)); - microApps = [...microApps, ...unregisteredApps]; + microApps.push(...unregisteredApps); unregisteredApps.forEach((app) => { const { name, activeRule, loader = noop, props, entry, container } = app; diff --git a/packages/qiankun/src/core/loadApp.ts b/packages/qiankun/src/core/loadApp.ts index 85b528b2e..2a54eca5c 100644 --- a/packages/qiankun/src/core/loadApp.ts +++ b/packages/qiankun/src/core/loadApp.ts @@ -30,7 +30,7 @@ export default async function loadApp( ): Promise { const { name: appName, entry, container } = app; const defaultNodeTransformer: AppConfiguration['nodeTransformer'] = (node, opts) => { - const moduleResolver = (url: string) => defaultModuleResolver(url, sandboxMicroAppContainer, document.head); + const moduleResolver = (url: string) => defaultModuleResolver(url, microAppDOMContainer, document.head); return transpileAssets(node, entry, { ...opts, moduleResolver }); }; const { @@ -49,15 +49,15 @@ export default async function loadApp( } let global = globalContext; - let mountSandbox = () => Promise.resolve(); + let mountSandbox: (container: HTMLElement) => Promise = () => Promise.resolve(); let unmountSandbox = () => Promise.resolve(); let sandboxInstance: Sandbox | undefined; - let sandboxMicroAppContainer: HTMLElement = container; - initContainer(sandboxMicroAppContainer, appName, sandbox); + let microAppDOMContainer: HTMLElement = container; + initContainer(microAppDOMContainer, appName, sandbox); if (sandbox) { - const sandboxContainer = createSandboxContainer(appName, () => sandboxMicroAppContainer, { + const sandboxContainer = createSandboxContainer(appName, () => microAppDOMContainer, { globalContext, extraGlobals: {}, fetch: fetchWithLruCache, @@ -67,7 +67,7 @@ export default async function loadApp( sandboxInstance = sandboxContainer.instance; global = sandboxInstance.globalThis; - mountSandbox = () => sandboxContainer.mount(); + mountSandbox = (domContainer) => sandboxContainer.mount(domContainer); unmountSandbox = () => sandboxContainer.unmount(); } @@ -78,7 +78,7 @@ export default async function loadApp( ...restConfiguration, }; - const lifecyclesPromise = loadEntry(entry, sandboxMicroAppContainer, containerOpts); + const lifecyclesPromise = loadEntry(entry, microAppDOMContainer, containerOpts); const assetPublicPath = calcPublicPath(entry); const { @@ -123,7 +123,7 @@ export default async function loadApp( } }, async () => { - sandboxMicroAppContainer = mountContainer; + microAppDOMContainer = mountContainer; // while the micro app is remounting, we need to load the entry manually if (mountTimes > 1) { @@ -133,7 +133,9 @@ export default async function loadApp( await loadEntry(htmlString, mountContainer, containerOpts); } }, - mountSandbox, + async () => { + await mountSandbox(mountContainer); + }, // exec the chain after rendering to keep the behavior with beforeLoad async () => execHooksChain(toArray(beforeMount), app, global), async (props) => mount({ ...props, container: mountContainer }), diff --git a/packages/sandbox/src/core/compartment/index.ts b/packages/sandbox/src/core/compartment/index.ts index aae93b39c..5cff17bcd 100644 --- a/packages/sandbox/src/core/compartment/index.ts +++ b/packages/sandbox/src/core/compartment/index.ts @@ -15,8 +15,6 @@ type CompartmentGlobalId = `${typeof compartmentGlobalIdPrefix}${string}${typeof declare global { interface Window { - __compartment_window__?: Window; - [p: CompartmentGlobalId]: WindowProxy | undefined; } } diff --git a/packages/sandbox/src/core/sandbox/index.ts b/packages/sandbox/src/core/sandbox/index.ts index 525d103a0..6f3dabdab 100644 --- a/packages/sandbox/src/core/sandbox/index.ts +++ b/packages/sandbox/src/core/sandbox/index.ts @@ -12,17 +12,6 @@ import type { Sandbox } from './types'; export type { Sandbox }; /** - * 生成应用运行时沙箱 - * - * 沙箱分两个类型: - * 1. app 环境沙箱 - * app 环境沙箱是指应用初始化过之后,应用会在什么样的上下文环境运行。每个应用的环境沙箱只会初始化一次,因为子应用只会触发一次 bootstrap 。 - * 子应用在切换时,实际上切换的是 app 环境沙箱。 - * 2. render 沙箱 - * 子应用在 app mount 开始前生成好的的沙箱。每次子应用切换过后,render 沙箱都会重现初始化。 - * - * 这么设计的目的是为了保证每个子应用切换回来之后,还能运行在应用 bootstrap 之后的环境下。 - * * @param appName * @param getContainer * @param opts @@ -60,7 +49,7 @@ export function createSandboxContainer( * 可能是从 bootstrap 状态进入的 mount * 也可能是从 unmount 之后再次唤醒进入 mount */ - async mount() { + async mount(container: HTMLElement) { /* ------------------------------------------ 因为有上下文依赖(window),以下代码执行顺序不能变 ------------------------------------------ */ /* ------------------------------------------ 1. 启动/恢复 沙箱------------------------------------------ */ @@ -72,7 +61,7 @@ export function createSandboxContainer( // must rebuild the side effects which added at bootstrapping firstly to recovery to nature state if (sideEffectsRebuildsAtBootstrapping.length) { for (const rebuildSideEffects of sideEffectsRebuildsAtBootstrapping) { - await rebuildSideEffects(); + await rebuildSideEffects(container); } } @@ -80,11 +69,11 @@ export function createSandboxContainer( // render 沙箱启动时开始劫持各类全局监听,尽量不要在应用初始化阶段有 事件监听/定时器 等副作用 mountingFrees = patchAtMounting(appName, getContainer, { sandbox, ...sandboxCfg }); - /* ------------------------------------------ 3. 重置一些初始化时的副作用 ------------------------------------------*/ + /* ------------------------------------------ 3. 重置一些初始化时的副作用 ------------------------------------*/ // 存在 rebuilds 则表明有些副作用需要重建 if (sideEffectsRebuildsAtMounting.length) { for (const rebuildSideEffects of sideEffectsRebuildsAtMounting) { - await rebuildSideEffects(); + await rebuildSideEffects(container); } } diff --git a/packages/sandbox/src/core/sandbox/types.ts b/packages/sandbox/src/core/sandbox/types.ts index 27256a6d6..42c67e5f6 100644 --- a/packages/sandbox/src/core/sandbox/types.ts +++ b/packages/sandbox/src/core/sandbox/types.ts @@ -19,6 +19,8 @@ export interface Sandbox extends Compartment { inactive(): void; + destroy(): void; + addIntrinsics: (intrinsics: Record) => void; // TODO for gc diff --git a/packages/sandbox/src/patchers/dynamicAppend/forStandardSandbox.ts b/packages/sandbox/src/patchers/dynamicAppend/forStandardSandbox.ts index d03bf0933..4175c8c67 100644 --- a/packages/sandbox/src/patchers/dynamicAppend/forStandardSandbox.ts +++ b/packages/sandbox/src/patchers/dynamicAppend/forStandardSandbox.ts @@ -31,7 +31,6 @@ declare global { } interface Window { - __sandboxConfigWeakMap__?: WeakMap; __currentLockingSandbox__?: Sandbox; } @@ -49,9 +48,7 @@ Object.defineProperty(nativeGlobal, '__currentLockingSandbox__', { configurable: true, }); -// Share sandboxConfigWeakMap between multiple qiankun instance, thus they could access the same record -nativeGlobal.__sandboxConfigWeakMap__ = nativeGlobal.__sandboxConfigWeakMap__ || new WeakMap(); -const sandboxConfigWeakMap = nativeGlobal.__sandboxConfigWeakMap__; +const sandboxConfigWeakMap = new WeakMap(); const elementAttachSandboxConfigMap = new WeakMap(); const patchCacheWeakMap = new WeakMap(); @@ -356,8 +353,7 @@ export function patchStandardSandbox( // As now the sub app content all wrapped with a special id container, // the dynamic style sheet could be removed automatically while unmounting - return async function rebuild() { - const container = getContainer(); + return async function rebuild(container: HTMLElement) { const isElementExisted = (element: HTMLStyleElement | HTMLLinkElement) => { if (container.contains(element)) return true; if ('rel' in element && element.rel === 'stylesheet' && element.href) diff --git a/packages/sandbox/src/patchers/types.ts b/packages/sandbox/src/patchers/types.ts index 4c482924d..b939f9a2d 100644 --- a/packages/sandbox/src/patchers/types.ts +++ b/packages/sandbox/src/patchers/types.ts @@ -2,6 +2,6 @@ * @author Kuitos * @since 2023-05-04 */ -export type Rebuild = () => Promise; +export type Rebuild = (container: HTMLElement) => Promise; export type Free = () => Rebuild; export type Patch = () => Free;