🐛 fix the counter issue while multiple apps mounting concurrently (#2250)

This commit is contained in:
Kuitos 2022-08-26 14:23:03 +08:00 committed by GitHub
parent 59da80eb9c
commit a5a0273a11
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 45 additions and 21 deletions

View File

@ -67,6 +67,32 @@ export function isStyledComponentsLike(element: HTMLStyleElement) {
);
}
const appsCounterMap = new Map<string, { bootstrappingPatchCount: number; mountingPatchCount: number }>();
export function calcAppCount(
appName: string,
calcType: 'increase' | 'decrease',
status: 'bootstrapping' | 'mounting',
): void {
const appCount = appsCounterMap.get(appName) || { bootstrappingPatchCount: 0, mountingPatchCount: 0 };
switch (calcType) {
case 'increase':
appCount[`${status}PatchCount`] += 1;
break;
case 'decrease':
// bootstrap patch just called once but its freer will be called multiple times
if (appCount[`${status}PatchCount`] > 0) {
appCount[`${status}PatchCount`] -= 1;
}
break;
}
appsCounterMap.set(appName, appCount);
}
export function isAllAppsUnmounted(): boolean {
return Array.from(appsCounterMap.entries()).every(
([, { bootstrappingPatchCount: bpc, mountingPatchCount: mpc }]) => bpc === 0 && mpc === 0,
);
}
function patchCustomEvent(
e: CustomEvent,
elementGetter: () => HTMLScriptElement | HTMLLinkElement | null,

View File

@ -5,10 +5,13 @@
import { checkActivityFunctions } from 'single-spa';
import type { Freer } from '../../../interfaces';
import { patchHTMLDynamicAppendPrototypeFunctions, rebuildCSSRules, recordStyledComponentsCSSRules } from './common';
let bootstrappingPatchCount = 0;
let mountingPatchCount = 0;
import {
calcAppCount,
isAllAppsUnmounted,
patchHTMLDynamicAppendPrototypeFunctions,
rebuildCSSRules,
recordStyledComponentsCSSRules,
} from './common';
/**
* Just hijack dynamic head append, that could avoid accidentally hijacking the insertion of elements except in head.
@ -52,17 +55,15 @@ export function patchLooseSandbox(
}),
);
if (!mounting) bootstrappingPatchCount++;
if (mounting) mountingPatchCount++;
if (!mounting) calcAppCount(appName, 'increase', 'bootstrapping');
if (mounting) calcAppCount(appName, 'increase', 'mounting');
return function free() {
// bootstrap patch just called once but its freer will be called multiple times
if (!mounting && bootstrappingPatchCount !== 0) bootstrappingPatchCount--;
if (mounting) mountingPatchCount--;
if (!mounting) calcAppCount(appName, 'decrease', 'bootstrapping');
if (mounting) calcAppCount(appName, 'decrease', 'mounting');
const allMicroAppUnmounted = mountingPatchCount === 0 && bootstrappingPatchCount === 0;
// release the overwrite prototype after all the micro apps unmounted
if (allMicroAppUnmounted) unpatchDynamicAppendPrototypeFunctions();
if (isAllAppsUnmounted()) unpatchDynamicAppendPrototypeFunctions();
recordStyledComponentsCSSRules(dynamicStyleSheetElements);

View File

@ -8,7 +8,9 @@ import { nativeGlobal } from '../../../utils';
import { getCurrentRunningApp } from '../../common';
import type { ContainerConfig } from './common';
import {
calcAppCount,
getAppWrapperHeadElement,
isAllAppsUnmounted,
isHijackingTag,
patchHTMLDynamicAppendPrototypeFunctions,
rawHeadAppendChild,
@ -74,9 +76,6 @@ function patchDocumentCreateElement() {
};
}
let bootstrappingPatchCount = 0;
let mountingPatchCount = 0;
export function patchStrictSandbox(
appName: string,
appWrapperGetter: () => HTMLElement | ShadowRoot,
@ -108,17 +107,15 @@ export function patchStrictSandbox(
(element) => elementAttachContainerConfigMap.get(element)!,
);
if (!mounting) bootstrappingPatchCount++;
if (mounting) mountingPatchCount++;
if (!mounting) calcAppCount(appName, 'increase', 'bootstrapping');
if (mounting) calcAppCount(appName, 'increase', 'mounting');
return function free() {
// bootstrap patch just called once but its freer will be called multiple times
if (!mounting && bootstrappingPatchCount !== 0) bootstrappingPatchCount--;
if (mounting) mountingPatchCount--;
if (!mounting) calcAppCount(appName, 'decrease', 'bootstrapping');
if (mounting) calcAppCount(appName, 'decrease', 'mounting');
const allMicroAppUnmounted = mountingPatchCount === 0 && bootstrappingPatchCount === 0;
// release the overwritten prototype after all the micro apps unmounted
if (allMicroAppUnmounted) {
if (isAllAppsUnmounted()) {
unpatchDynamicAppendPrototypeFunctions();
unpatchDocumentCreate();
}