🐛 re-process the internal style in element after app remount (#1006)

This commit is contained in:
Kuitos 2020-10-20 11:06:15 +08:00 committed by GitHub
parent f130a10ab6
commit 9e5b9da2ee

View File

@ -53,7 +53,12 @@ async function validateSingularMode<T extends object>(
// @ts-ignore // @ts-ignore
const supportShadowDOM = document.head.attachShadow || document.head.createShadowRoot; const supportShadowDOM = document.head.attachShadow || document.head.createShadowRoot;
function createElement(appContent: string, strictStyleIsolation: boolean): HTMLElement { function createElement(
appContent: string,
strictStyleIsolation: boolean,
scopedCSS: boolean,
appName: string,
): HTMLElement {
const containerElement = document.createElement('div'); const containerElement = document.createElement('div');
containerElement.innerHTML = appContent; containerElement.innerHTML = appContent;
// appContent always wrapped with a singular div // appContent always wrapped with a singular div
@ -78,6 +83,18 @@ function createElement(appContent: string, strictStyleIsolation: boolean): HTMLE
} }
} }
if (scopedCSS) {
const attr = appElement.getAttribute(css.QiankunCSSRewriteAttr);
if (!attr) {
appElement.setAttribute(css.QiankunCSSRewriteAttr, appName);
}
const styleNodes = appElement.querySelectorAll('style') || [];
forEach(styleNodes, (stylesheetElement: HTMLStyleElement) => {
css.process(appElement!, stylesheetElement, appName);
});
}
return appElement; return appElement;
} }
@ -87,13 +104,13 @@ function getAppWrapperGetter(
appInstanceId: string, appInstanceId: string,
useLegacyRender: boolean, useLegacyRender: boolean,
strictStyleIsolation: boolean, strictStyleIsolation: boolean,
enableScopedCSS: boolean, scopedCSS: boolean,
elementGetter: () => HTMLElement | null, elementGetter: () => HTMLElement | null,
) { ) {
return () => { return () => {
if (useLegacyRender) { if (useLegacyRender) {
if (strictStyleIsolation) throw new Error('[qiankun]: strictStyleIsolation can not be used with legacy render!'); if (strictStyleIsolation) throw new Error('[qiankun]: strictStyleIsolation can not be used with legacy render!');
if (enableScopedCSS) throw new Error('[qiankun]: experimentalStyleIsolation can not be used with legacy render!'); if (scopedCSS) throw new Error('[qiankun]: experimentalStyleIsolation can not be used with legacy render!');
const appWrapper = document.getElementById(getWrapperId(appInstanceId)); const appWrapper = document.getElementById(getWrapperId(appInstanceId));
assertElementExist( assertElementExist(
@ -109,13 +126,6 @@ function getAppWrapperGetter(
`[qiankun] Wrapper element for ${appName} with instance ${appInstanceId} is not existed!`, `[qiankun] Wrapper element for ${appName} with instance ${appInstanceId} is not existed!`,
); );
if (enableScopedCSS) {
const attr = element!.getAttribute(css.QiankunCSSRewriteAttr);
if (!attr) {
element!.setAttribute(css.QiankunCSSRewriteAttr, appName);
}
}
if (strictStyleIsolation) { if (strictStyleIsolation) {
return element!.shadowRoot!; return element!.shadowRoot!;
} }
@ -247,14 +257,8 @@ export async function loadApp<T extends object>(
const appContent = getDefaultTplWrapper(appInstanceId, appName)(template); const appContent = getDefaultTplWrapper(appInstanceId, appName)(template);
const strictStyleIsolation = typeof sandbox === 'object' && !!sandbox.strictStyleIsolation; const strictStyleIsolation = typeof sandbox === 'object' && !!sandbox.strictStyleIsolation;
let appWrapperElement: HTMLElement | null = createElement(appContent, strictStyleIsolation); const scopedCSS = isEnableScopedCSS(sandbox);
const enableScopedCSS = isEnableScopedCSS(sandbox); let appWrapperElement: HTMLElement | null = createElement(appContent, strictStyleIsolation, scopedCSS, appName);
if (appWrapperElement && enableScopedCSS) {
const styleNodes = appWrapperElement.querySelectorAll('style') || [];
forEach(styleNodes, (stylesheetElement: HTMLStyleElement) => {
css.process(appWrapperElement!, stylesheetElement, appName);
});
}
const container = 'container' in app ? app.container : undefined; const container = 'container' in app ? app.container : undefined;
const legacyRender = 'render' in app ? app.render : undefined; const legacyRender = 'render' in app ? app.render : undefined;
@ -270,7 +274,7 @@ export async function loadApp<T extends object>(
appInstanceId, appInstanceId,
!!legacyRender, !!legacyRender,
strictStyleIsolation, strictStyleIsolation,
enableScopedCSS, scopedCSS,
() => appWrapperElement, () => appWrapperElement,
); );
@ -279,13 +283,7 @@ export async function loadApp<T extends object>(
let unmountSandbox = () => Promise.resolve(); let unmountSandbox = () => Promise.resolve();
const useLooseSandbox = typeof sandbox === 'object' && !!sandbox.loose; const useLooseSandbox = typeof sandbox === 'object' && !!sandbox.loose;
if (sandbox) { if (sandbox) {
const sandboxInstance = createSandbox( const sandboxInstance = createSandbox(appName, appWrapperGetter, scopedCSS, useLooseSandbox, excludeAssetFilter);
appName,
appWrapperGetter,
enableScopedCSS,
useLooseSandbox,
excludeAssetFilter,
);
// 用沙箱的代理对象作为接下来使用的全局对象 // 用沙箱的代理对象作为接下来使用的全局对象
global = sandboxInstance.proxy as typeof window; global = sandboxInstance.proxy as typeof window;
mountSandbox = sandboxInstance.mount; mountSandbox = sandboxInstance.mount;
@ -335,7 +333,7 @@ export async function loadApp<T extends object>(
// 添加 mount hook, 确保每次应用加载前容器 dom 结构已经设置完毕 // 添加 mount hook, 确保每次应用加载前容器 dom 结构已经设置完毕
async () => { async () => {
// element would be destroyed after unmounted, we need to recreate it if it not exist // element would be destroyed after unmounted, we need to recreate it if it not exist
appWrapperElement = appWrapperElement || createElement(appContent, strictStyleIsolation); appWrapperElement = appWrapperElement || createElement(appContent, strictStyleIsolation, scopedCSS, appName);
render({ element: appWrapperElement, loading: true, remountContainer }, 'mounting'); render({ element: appWrapperElement, loading: true, remountContainer }, 'mounting');
}, },
mountSandbox, mountSandbox,