Skip to content

Commit 6e5b145

Browse files
authored
🐛 compatible with overwritten appendChild by apps themselves (#2449)
1 parent 601696a commit 6e5b145

File tree

2 files changed

+33
-23
lines changed

2 files changed

+33
-23
lines changed

src/sandbox/patchers/dynamicAppend/common.ts

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,12 @@ import { qiankunHeadTagName } from '../../../utils';
99
import { cachedGlobals } from '../../proxySandbox';
1010
import * as css from '../css';
1111

12-
export const rawHeadAppendChild = HTMLHeadElement.prototype.appendChild;
13-
const rawHeadRemoveChild = HTMLHeadElement.prototype.removeChild;
14-
const rawBodyAppendChild = HTMLBodyElement.prototype.appendChild;
15-
const rawBodyRemoveChild = HTMLBodyElement.prototype.removeChild;
16-
const rawHeadInsertBefore = HTMLHeadElement.prototype.insertBefore;
17-
const rawRemoveChild = HTMLElement.prototype.removeChild;
18-
1912
const SCRIPT_TAG_NAME = 'SCRIPT';
2013
const LINK_TAG_NAME = 'LINK';
2114
const STYLE_TAG_NAME = 'STYLE';
2215

2316
export const styleElementTargetSymbol = Symbol('target');
17+
const overwrittenSymbol = Symbol('qiankun-overwritten');
2418

2519
type DynamicDomMutationTarget = 'head' | 'body';
2620

@@ -32,6 +26,10 @@ declare global {
3226
interface HTMLStyleElement {
3327
[styleElementTargetSymbol]: DynamicDomMutationTarget;
3428
}
29+
30+
interface Function {
31+
[overwrittenSymbol]: boolean;
32+
}
3533
}
3634

3735
export const getAppWrapperHeadElement = (appWrapper: Element | ShadowRoot): Element => {
@@ -69,6 +67,7 @@ export function isStyledComponentsLike(element: HTMLStyleElement) {
6967
}
7068

7169
const appsCounterMap = new Map<string, { bootstrappingPatchCount: number; mountingPatchCount: number }>();
70+
7271
export function calcAppCount(
7372
appName: string,
7473
calcType: 'increase' | 'decrease',
@@ -88,6 +87,7 @@ export function calcAppCount(
8887
}
8988
appsCounterMap.set(appName, appCount);
9089
}
90+
9191
export function isAllAppsUnmounted(): boolean {
9292
return Array.from(appsCounterMap.entries()).every(
9393
([, { bootstrappingPatchCount: bpc, mountingPatchCount: mpc }]) => bpc === 0 && mpc === 0,
@@ -197,7 +197,7 @@ function getOverwrittenAppendChildOrInsertBefore(opts: {
197197
containerConfigGetter: (element: HTMLElement) => ContainerConfig;
198198
target: DynamicDomMutationTarget;
199199
}) {
200-
return function appendChildOrInsertBefore<T extends Node>(
200+
function appendChildOrInsertBefore<T extends Node>(
201201
this: HTMLHeadElement | HTMLBodyElement,
202202
newChild: T,
203203
refChild: Node | null = null,
@@ -339,19 +339,22 @@ function getOverwrittenAppendChildOrInsertBefore(opts: {
339339
}
340340

341341
return rawDOMAppendOrInsertBefore.call(this, element, refChild);
342-
};
342+
}
343+
344+
appendChildOrInsertBefore[overwrittenSymbol] = true;
345+
346+
return appendChildOrInsertBefore;
343347
}
344348

345349
function getNewRemoveChild(
346-
headOrBodyRemoveChild: typeof HTMLElement.prototype.removeChild,
350+
rawRemoveChild: typeof HTMLElement.prototype.removeChild,
347351
containerConfigGetter: (element: HTMLElement) => ContainerConfig,
348352
target: DynamicDomMutationTarget,
349353
isInvokedByMicroApp: (element: HTMLElement) => boolean,
350354
) {
351-
return function removeChild<T extends Node>(this: HTMLHeadElement | HTMLBodyElement, child: T) {
355+
function removeChild<T extends Node>(this: HTMLHeadElement | HTMLBodyElement, child: T) {
352356
const { tagName } = child as any;
353-
if (!isHijackingTag(tagName) || !isInvokedByMicroApp(child as any))
354-
return headOrBodyRemoveChild.call(this, child) as T;
357+
if (!isHijackingTag(tagName) || !isInvokedByMicroApp(child as any)) return rawRemoveChild.call(this, child) as T;
355358

356359
try {
357360
let attachedElement: Node;
@@ -391,19 +394,26 @@ function getNewRemoveChild(
391394
console.warn(e);
392395
}
393396

394-
return headOrBodyRemoveChild.call(this, child) as T;
395-
};
397+
return rawRemoveChild.call(this, child) as T;
398+
}
399+
400+
removeChild[overwrittenSymbol] = true;
401+
return removeChild;
396402
}
397403

398404
export function patchHTMLDynamicAppendPrototypeFunctions(
399405
isInvokedByMicroApp: (element: HTMLElement) => boolean,
400406
containerConfigGetter: (element: HTMLElement) => ContainerConfig,
401407
) {
408+
const rawHeadAppendChild = HTMLHeadElement.prototype.appendChild;
409+
const rawBodyAppendChild = HTMLBodyElement.prototype.appendChild;
410+
const rawHeadInsertBefore = HTMLHeadElement.prototype.insertBefore;
411+
402412
// Just overwrite it while it have not been overwritten
403413
if (
404-
HTMLHeadElement.prototype.appendChild === rawHeadAppendChild &&
405-
HTMLBodyElement.prototype.appendChild === rawBodyAppendChild &&
406-
HTMLHeadElement.prototype.insertBefore === rawHeadInsertBefore
414+
rawHeadAppendChild[overwrittenSymbol] !== true &&
415+
rawBodyAppendChild[overwrittenSymbol] !== true &&
416+
rawHeadInsertBefore[overwrittenSymbol] !== true
407417
) {
408418
HTMLHeadElement.prototype.appendChild = getOverwrittenAppendChildOrInsertBefore({
409419
rawDOMAppendOrInsertBefore: rawHeadAppendChild,
@@ -426,11 +436,10 @@ export function patchHTMLDynamicAppendPrototypeFunctions(
426436
}) as typeof rawHeadInsertBefore;
427437
}
428438

439+
const rawHeadRemoveChild = HTMLHeadElement.prototype.removeChild;
440+
const rawBodyRemoveChild = HTMLBodyElement.prototype.removeChild;
429441
// Just overwrite it while it have not been overwritten
430-
if (
431-
HTMLHeadElement.prototype.removeChild === rawHeadRemoveChild &&
432-
HTMLBodyElement.prototype.removeChild === rawBodyRemoveChild
433-
) {
442+
if (rawHeadRemoveChild[overwrittenSymbol] !== true && rawBodyRemoveChild[overwrittenSymbol] !== true) {
434443
HTMLHeadElement.prototype.removeChild = getNewRemoveChild(
435444
rawHeadRemoveChild,
436445
containerConfigGetter,

src/sandbox/patchers/dynamicAppend/forStrictSandbox.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import {
1313
isAllAppsUnmounted,
1414
isHijackingTag,
1515
patchHTMLDynamicAppendPrototypeFunctions,
16-
rawHeadAppendChild,
1716
rebuildCSSRules,
1817
recordStyledComponentsCSSRules,
1918
styleElementTargetSymbol,
@@ -22,6 +21,8 @@ import {
2221
// Get native global window with a sandbox disgusted way, thus we could share it between qiankun instances🤪
2322
Object.defineProperty(nativeGlobal, '__proxyAttachContainerConfigMap__', { enumerable: false, writable: true });
2423

24+
const rawHeadAppendChild = HTMLHeadElement.prototype.appendChild;
25+
2526
// Share proxyAttachContainerConfigMap between multiple qiankun instance, thus they could access the same record
2627
nativeGlobal.__proxyAttachContainerConfigMap__ =
2728
nativeGlobal.__proxyAttachContainerConfigMap__ || new WeakMap<WindowProxy, ContainerConfig>();

0 commit comments

Comments
 (0)