From 69759a57e5e9a455bf583ee565f47d9237f1552e Mon Sep 17 00:00:00 2001 From: Kuitos Date: Mon, 7 Aug 2023 14:19:07 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20keep=20dynamic=20stylesheet=20in?= =?UTF-8?q?serted=20order=20by=20insertBefore=20way=20(#2574)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/sandbox/patchers/dynamicAppend/common.ts | 36 +++++++++++++++---- .../dynamicAppend/forStrictSandbox.ts | 16 +++++++-- 2 files changed, 43 insertions(+), 9 deletions(-) diff --git a/src/sandbox/patchers/dynamicAppend/common.ts b/src/sandbox/patchers/dynamicAppend/common.ts index 221d5f2..22fe001 100644 --- a/src/sandbox/patchers/dynamicAppend/common.ts +++ b/src/sandbox/patchers/dynamicAppend/common.ts @@ -14,6 +14,7 @@ const LINK_TAG_NAME = 'LINK'; const STYLE_TAG_NAME = 'STYLE'; export const styleElementTargetSymbol = Symbol('target'); +export const styleElementRefNodeNo = Symbol('refNodeNo'); const overwrittenSymbol = Symbol('qiankun-overwritten'); type DynamicDomMutationTarget = 'head' | 'body'; @@ -21,10 +22,12 @@ type DynamicDomMutationTarget = 'head' | 'body'; declare global { interface HTMLLinkElement { [styleElementTargetSymbol]: DynamicDomMutationTarget; + [styleElementRefNodeNo]?: number; } interface HTMLStyleElement { [styleElementTargetSymbol]: DynamicDomMutationTarget; + [styleElementRefNodeNo]?: number; } interface Function { @@ -156,6 +159,15 @@ function convertLinkAsStyle( return styleElement; } +const defineNonEnumerableProperty = (target: any, key: string | symbol, value: any) => { + Object.defineProperty(target, key, { + configurable: true, + enumerable: false, + writable: true, + value, + }); +}; + const styledComponentCSSRulesMap = new WeakMap(); const dynamicScriptAttachedCommentMap = new WeakMap(); const dynamicLinkAttachedInlineStyleMap = new WeakMap(); @@ -230,11 +242,7 @@ function getOverwrittenAppendChildOrInsertBefore(opts: { return rawDOMAppendOrInsertBefore.call(this, element, refChild) as T; } - Object.defineProperty(stylesheetElement, styleElementTargetSymbol, { - value: target, - writable: true, - configurable: true, - }); + defineNonEnumerableProperty(stylesheetElement, styleElementTargetSymbol, target); const appWrapper = appWrapperGetter(); @@ -262,9 +270,23 @@ function getOverwrittenAppendChildOrInsertBefore(opts: { const mountDOM = target === 'head' ? getAppWrapperHeadElement(appWrapper) : appWrapper; - dynamicStyleSheetElements.push(stylesheetElement); const referenceNode = mountDOM.contains(refChild) ? refChild : null; - return rawDOMAppendOrInsertBefore.call(mountDOM, stylesheetElement, referenceNode); + + let refNo: number | undefined; + if (referenceNode) { + refNo = Array.from(mountDOM.childNodes).indexOf(referenceNode); + } + + const result = rawDOMAppendOrInsertBefore.call(mountDOM, stylesheetElement, referenceNode); + + // record refNo thus we can keep order while remounting + if (typeof refNo === 'number' && refNo !== -1) { + defineNonEnumerableProperty(stylesheetElement, styleElementRefNodeNo, refNo); + } + // record dynamic style elements after insert succeed + dynamicStyleSheetElements.push(stylesheetElement); + + return result as T; } case SCRIPT_TAG_NAME: { diff --git a/src/sandbox/patchers/dynamicAppend/forStrictSandbox.ts b/src/sandbox/patchers/dynamicAppend/forStrictSandbox.ts index 34ba276..4d8622d 100644 --- a/src/sandbox/patchers/dynamicAppend/forStrictSandbox.ts +++ b/src/sandbox/patchers/dynamicAppend/forStrictSandbox.ts @@ -15,6 +15,7 @@ import { patchHTMLDynamicAppendPrototypeFunctions, rebuildCSSRules, recordStyledComponentsCSSRules, + styleElementRefNodeNo, styleElementTargetSymbol, } from './common'; @@ -35,6 +36,7 @@ Object.defineProperty(nativeGlobal, '__currentLockingSandbox__', { }); const rawHeadAppendChild = HTMLHeadElement.prototype.appendChild; +const rawHeadInsertBefore = HTMLHeadElement.prototype.insertBefore; // Share proxyAttachContainerConfigMap between multiple qiankun instance, thus they could access the same record nativeGlobal.__proxyAttachContainerConfigMap__ = @@ -279,8 +281,18 @@ export function patchStrictSandbox( if (!appWrapper.contains(stylesheetElement)) { const mountDom = stylesheetElement[styleElementTargetSymbol] === 'head' ? getAppWrapperHeadElement(appWrapper) : appWrapper; - rawHeadAppendChild.call(mountDom, stylesheetElement); - return true; + const refNo = stylesheetElement[styleElementRefNodeNo]; + + if (typeof refNo === 'number' && refNo !== -1) { + const refNode = mountDom.childNodes[refNo]; + if (refNode) { + rawHeadInsertBefore.call(mountDom, stylesheetElement, refNode); + return true; + } + } else { + rawHeadAppendChild.call(mountDom, stylesheetElement); + return true; + } } return false;