diff --git a/examples/main/index.js b/examples/main/index.js
index 8dcfe9dcf..d0c54580f 100644
--- a/examples/main/index.js
+++ b/examples/main/index.js
@@ -1,12 +1,12 @@
import 'zone.js'; // for angular subapp
-import { registerMicroApps, runAfterFirstMounted, setDefaultMountApp, start, initGlobalState } from '../../es';
+import { initGlobalState, registerMicroApps, runAfterFirstMounted, setDefaultMountApp, start } from '../../es';
import './index.less';
-
/**
* 主应用 **可以使用任意技术栈**
* 以下分别是 React 和 Vue 的示例,可切换尝试
*/
import render from './render/ReactRender';
+
// import render from './render/VueRender';
/**
@@ -14,7 +14,7 @@ import render from './render/ReactRender';
*/
render({ loading: true });
-const loader = loading => render({ loading });
+const loader = (loading) => render({ loading });
/**
* Step2 注册子应用
@@ -67,17 +67,17 @@ registerMicroApps(
],
{
beforeLoad: [
- app => {
+ (app) => {
console.log('[LifeCycle] before load %c%s', 'color: green;', app.name);
},
],
beforeMount: [
- app => {
+ (app) => {
console.log('[LifeCycle] before mount %c%s', 'color: green;', app.name);
},
],
afterUnmount: [
- app => {
+ (app) => {
console.log('[LifeCycle] after unmount %c%s', 'color: green;', app.name);
},
],
diff --git a/examples/react15/index.js b/examples/react15/index.js
index 54d2dbf5e..750416ebc 100644
--- a/examples/react15/index.js
+++ b/examples/react15/index.js
@@ -2,13 +2,12 @@
* @author Kuitos
* @since 2019-05-16
*/
-import './public-path';
+import 'antd/dist/antd.min.css';
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
-
-import 'antd/dist/antd.min.css';
import './index.css';
+import './public-path';
export async function bootstrap() {
console.log('[react15] react app bootstraped');
@@ -24,6 +23,14 @@ export async function mount(props = {}) {
import('./dynamic.css').then(() => {
console.log('[react15] dynamic style load');
});
+
+ const styleElement = document.createElement('style');
+ styleElement.innerText = '.react15-icon { height: 400px }';
+ document.head.appendChild(styleElement);
+
+ setTimeout(() => {
+ document.head.removeChild(styleElement);
+ }, 2000);
}
export async function unmount(props) {
diff --git a/src/__tests__/utils.test.ts b/src/__tests__/utils.test.ts
index 2fb1683d8..6eb047779 100644
--- a/src/__tests__/utils.test.ts
+++ b/src/__tests__/utils.test.ts
@@ -29,7 +29,8 @@ test('should wrap string with div', () => {
const ret = factory(tpl);
expect(ret).toBe(
- `
${tpl}
`,
+ // eslint-disable-next-line max-len
+ `${tpl}
`,
);
});
diff --git a/src/sandbox/patchers/dynamicAppend/common.ts b/src/sandbox/patchers/dynamicAppend/common.ts
index 3e62daf29..c301e83c6 100644
--- a/src/sandbox/patchers/dynamicAppend/common.ts
+++ b/src/sandbox/patchers/dynamicAppend/common.ts
@@ -21,19 +21,19 @@ const STYLE_TAG_NAME = 'STYLE';
export const styleElementTargetSymbol = Symbol('target');
-type DynamicAppendTarget = 'head' | 'body';
+type DynamicDomMutationTarget = 'head' | 'body';
declare global {
interface HTMLLinkElement {
- [styleElementTargetSymbol]: DynamicAppendTarget;
+ [styleElementTargetSymbol]: DynamicDomMutationTarget;
}
interface HTMLStyleElement {
- [styleElementTargetSymbol]: DynamicAppendTarget;
+ [styleElementTargetSymbol]: DynamicDomMutationTarget;
}
}
-export const getAppWrapperHeadElement = (appWrapper: Element | ShadowRoot) => {
+export const getAppWrapperHeadElement = (appWrapper: Element | ShadowRoot): Element => {
const rootElement = 'host' in appWrapper ? appWrapper.host : appWrapper;
return rootElement.getElementsByTagName(qiankunHeadTagName)[0];
};
@@ -158,7 +158,7 @@ export type ContainerConfig = {
appName: string;
proxy: WindowProxy;
strictGlobal: boolean;
- dynamicStyleSheetElements: HTMLStyleElement[];
+ dynamicStyleSheetElements: Array;
appWrapperGetter: CallableFunction;
scopedCSS: boolean;
excludeAssetFilter?: CallableFunction;
@@ -168,7 +168,7 @@ function getOverwrittenAppendChildOrInsertBefore(opts: {
rawDOMAppendOrInsertBefore: (newChild: T, refChild?: Node | null) => T;
isInvokedByMicroApp: (element: HTMLElement) => boolean;
containerConfigGetter: (element: HTMLElement) => ContainerConfig;
- target: DynamicAppendTarget;
+ target: DynamicDomMutationTarget;
}) {
return function appendChildOrInsertBefore(
this: HTMLHeadElement | HTMLBodyElement,
@@ -209,7 +209,6 @@ function getOverwrittenAppendChildOrInsertBefore(opts: {
});
const appWrapper = appWrapperGetter();
- const mountDOM = target === 'head' ? getAppWrapperHeadElement(appWrapper) : appWrapper;
if (scopedCSS) {
// exclude link elements like
@@ -224,16 +223,17 @@ function getOverwrittenAppendChildOrInsertBefore(opts: {
: frameworkConfiguration.fetch?.fn;
stylesheetElement = convertLinkAsStyle(
element,
- (styleElement) => css.process(mountDOM, styleElement, appName),
+ (styleElement) => css.process(appWrapper, styleElement, appName),
fetch,
);
dynamicLinkAttachedInlineStyleMap.set(element, stylesheetElement);
} else {
- css.process(mountDOM, stylesheetElement, appName);
+ css.process(appWrapper, stylesheetElement, appName);
}
}
- // eslint-disable-next-line no-shadow
+ const mountDOM = target === 'head' ? getAppWrapperHeadElement(appWrapper) : appWrapper;
+
dynamicStyleSheetElements.push(stylesheetElement);
const referenceNode = mountDOM.contains(refChild) ? refChild : null;
return rawDOMAppendOrInsertBefore.call(mountDOM, stylesheetElement, referenceNode);
@@ -301,7 +301,8 @@ function getOverwrittenAppendChildOrInsertBefore(opts: {
function getNewRemoveChild(
headOrBodyRemoveChild: typeof HTMLElement.prototype.removeChild,
- appWrapperGetterGetter: (element: HTMLElement) => ContainerConfig['appWrapperGetter'],
+ containerConfigGetter: (element: HTMLElement) => ContainerConfig,
+ target: DynamicDomMutationTarget,
) {
return function removeChild(this: HTMLHeadElement | HTMLBodyElement, child: T) {
const { tagName } = child as any;
@@ -309,14 +310,19 @@ function getNewRemoveChild(
try {
let attachedElement: Node;
+ const { appWrapperGetter, dynamicStyleSheetElements } = containerConfigGetter(child as any);
+
switch (tagName) {
+ case STYLE_TAG_NAME:
case LINK_TAG_NAME: {
- attachedElement = (dynamicLinkAttachedInlineStyleMap.get(child as any) as Node) || child;
+ attachedElement = dynamicLinkAttachedInlineStyleMap.get(child as any) || child;
+ // try to remove the dynamic style sheet
+ dynamicStyleSheetElements.splice(dynamicStyleSheetElements.indexOf(attachedElement as any), 1);
break;
}
case SCRIPT_TAG_NAME: {
- attachedElement = (dynamicScriptAttachedCommentMap.get(child as any) as Node) || child;
+ attachedElement = dynamicScriptAttachedCommentMap.get(child as any) || child;
break;
}
@@ -325,11 +331,11 @@ function getNewRemoveChild(
}
}
- // container may had been removed while app unmounting if the removeChild action was async
- const appWrapperGetter = appWrapperGetterGetter(child as any);
- const container = appWrapperGetter();
+ const appWrapper = appWrapperGetter();
+ const container = target === 'head' ? getAppWrapperHeadElement(appWrapper) : appWrapper;
+ // container might have been removed while app unmounting if the removeChild action was async
if (container.contains(attachedElement)) {
- return rawRemoveChild.call(container, attachedElement) as T;
+ return rawRemoveChild.call(attachedElement.parentNode, attachedElement) as T;
}
} catch (e) {
console.warn(e);
@@ -375,14 +381,8 @@ export function patchHTMLDynamicAppendPrototypeFunctions(
HTMLHeadElement.prototype.removeChild === rawHeadRemoveChild &&
HTMLBodyElement.prototype.removeChild === rawBodyRemoveChild
) {
- HTMLHeadElement.prototype.removeChild = getNewRemoveChild(
- rawHeadRemoveChild,
- (element) => containerConfigGetter(element).appWrapperGetter,
- );
- HTMLBodyElement.prototype.removeChild = getNewRemoveChild(
- rawBodyRemoveChild,
- (element) => containerConfigGetter(element).appWrapperGetter,
- );
+ HTMLHeadElement.prototype.removeChild = getNewRemoveChild(rawHeadRemoveChild, containerConfigGetter, 'head');
+ HTMLBodyElement.prototype.removeChild = getNewRemoveChild(rawBodyRemoveChild, containerConfigGetter, 'body');
}
return function unpatch() {
diff --git a/src/sandbox/patchers/dynamicAppend/forStrictSandbox.ts b/src/sandbox/patchers/dynamicAppend/forStrictSandbox.ts
index c301b4e6c..7f003143a 100644
--- a/src/sandbox/patchers/dynamicAppend/forStrictSandbox.ts
+++ b/src/sandbox/patchers/dynamicAppend/forStrictSandbox.ts
@@ -117,7 +117,7 @@ export function patchStrictSandbox(
if (mounting) mountingPatchCount--;
const allMicroAppUnmounted = mountingPatchCount === 0 && bootstrappingPatchCount === 0;
- // release the overwrite prototype after all the micro apps unmounted
+ // release the overwritten prototype after all the micro apps unmounted
if (allMicroAppUnmounted) {
unpatchDynamicAppendPrototypeFunctions();
unpatchDocumentCreate();
diff --git a/src/utils.ts b/src/utils.ts
index 18cc1d122..c81e72358 100644
--- a/src/utils.ts
+++ b/src/utils.ts
@@ -107,10 +107,18 @@ export const qiankunHeadTagName = 'qiankun-head';
export function getDefaultTplWrapper(name: string) {
return (tpl: string) => {
- // We need to mock a head placeholder as native head element will be erased by browser in micro app
- const tplWithSimulatedHead = tpl
- .replace('', `<${qiankunHeadTagName}>`)
- .replace('', `${qiankunHeadTagName}>`);
+ let tplWithSimulatedHead: string;
+
+ if (tpl.indexOf('') !== -1) {
+ // We need to mock a head placeholder as native head element will be erased by browser in micro app
+ tplWithSimulatedHead = tpl
+ .replace('', `<${qiankunHeadTagName}>`)
+ .replace('', `${qiankunHeadTagName}>`);
+ } else {
+ // Some template might not be a standard html document, thus we need to add a simulated head tag for them
+ tplWithSimulatedHead = `<${qiankunHeadTagName}>${qiankunHeadTagName}>${tpl}`;
+ }
+
return `${tplWithSimulatedHead}
`;
diff --git a/src/version.ts b/src/version.ts
index a7250834f..edf45a6b4 100644
--- a/src/version.ts
+++ b/src/version.ts
@@ -1 +1 @@
-export { version } from '../package.json';
+export const version = '2.7.1';