🐛 keep the lifecycle execution order while multiple apps mounting on the same container parallelly (#1625)
This commit is contained in:
parent
44ccad92de
commit
9e4274e3f8
58
src/apis.ts
58
src/apis.ts
|
|
@ -52,6 +52,7 @@ export function registerMicroApps<T extends ObjectType>(
|
||||||
}
|
}
|
||||||
|
|
||||||
const appConfigPromiseGetterMap = new Map<string, Promise<ParcelConfigObjectGetter>>();
|
const appConfigPromiseGetterMap = new Map<string, Promise<ParcelConfigObjectGetter>>();
|
||||||
|
const containerMicroAppsMap = new Map<string, MicroApp[]>();
|
||||||
|
|
||||||
export function loadMicroApp<T extends ObjectType>(
|
export function loadMicroApp<T extends ObjectType>(
|
||||||
app: LoadableApp<T>,
|
app: LoadableApp<T>,
|
||||||
|
|
@ -69,9 +70,39 @@ export function loadMicroApp<T extends ObjectType>(
|
||||||
return undefined;
|
return undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let microApp: MicroApp;
|
||||||
const wrapParcelConfigForRemount = (config: ParcelConfigObject): ParcelConfigObject => {
|
const wrapParcelConfigForRemount = (config: ParcelConfigObject): ParcelConfigObject => {
|
||||||
return {
|
const container = 'container' in app ? app.container : undefined;
|
||||||
|
|
||||||
|
let microAppConfig = config;
|
||||||
|
if (container) {
|
||||||
|
const xpath = getContainerXpath(container);
|
||||||
|
if (xpath) {
|
||||||
|
const containerMicroApps = containerMicroAppsMap.get(`${name}-${xpath}`);
|
||||||
|
if (containerMicroApps?.length) {
|
||||||
|
const mount = [
|
||||||
|
async () => {
|
||||||
|
// While there are multiple micro apps mounted on the same container, we must wait until the prev instances all had unmounted
|
||||||
|
// Otherwise it will lead some concurrent issues
|
||||||
|
const prevLoadMicroApps = containerMicroApps.slice(0, containerMicroApps.indexOf(microApp));
|
||||||
|
const prevLoadMicroAppsWhichNotBroken = prevLoadMicroApps.filter(
|
||||||
|
(v) => v.getStatus() !== 'LOAD_ERROR' && v.getStatus() !== 'SKIP_BECAUSE_BROKEN',
|
||||||
|
);
|
||||||
|
await Promise.all(prevLoadMicroAppsWhichNotBroken.map((v) => v.unmountPromise));
|
||||||
|
},
|
||||||
|
...toArray(microAppConfig.mount),
|
||||||
|
];
|
||||||
|
|
||||||
|
microAppConfig = {
|
||||||
...config,
|
...config,
|
||||||
|
mount,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...microAppConfig,
|
||||||
// empty bootstrap hook which should not run twice while it calling from cached micro app
|
// empty bootstrap hook which should not run twice while it calling from cached micro app
|
||||||
bootstrap: () => Promise.resolve(),
|
bootstrap: () => Promise.resolve(),
|
||||||
};
|
};
|
||||||
|
|
@ -123,7 +154,30 @@ export function loadMicroApp<T extends ObjectType>(
|
||||||
startSingleSpa({ urlRerouteOnly: frameworkConfiguration.urlRerouteOnly ?? defaultUrlRerouteOnly });
|
startSingleSpa({ urlRerouteOnly: frameworkConfiguration.urlRerouteOnly ?? defaultUrlRerouteOnly });
|
||||||
}
|
}
|
||||||
|
|
||||||
return mountRootParcel(memorizedLoadingFn, { domElement: document.createElement('div'), ...props });
|
microApp = mountRootParcel(memorizedLoadingFn, { domElement: document.createElement('div'), ...props });
|
||||||
|
|
||||||
|
// Store the microApps which they mounted on the same container
|
||||||
|
const container = 'container' in app ? app.container : undefined;
|
||||||
|
if (container) {
|
||||||
|
const xpath = getContainerXpath(container);
|
||||||
|
if (xpath) {
|
||||||
|
const key = `${name}-${xpath}`;
|
||||||
|
|
||||||
|
const microAppsRef = containerMicroAppsMap.get(key) || [];
|
||||||
|
microAppsRef.push(microApp);
|
||||||
|
containerMicroAppsMap.set(key, microAppsRef);
|
||||||
|
|
||||||
|
// gc after unmount
|
||||||
|
microApp.unmountPromise.finally(() => {
|
||||||
|
const index = microAppsRef.indexOf(microApp);
|
||||||
|
microAppsRef.splice(index, 1);
|
||||||
|
// @ts-ignore
|
||||||
|
microApp = null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return microApp;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function start(opts: FrameworkConfiguration = {}) {
|
export function start(opts: FrameworkConfiguration = {}) {
|
||||||
|
|
|
||||||
|
|
@ -341,15 +341,8 @@ export async function loadApp<T extends ObjectType>(
|
||||||
const syncAppWrapperElement2Sandbox = (element: HTMLElement | null) => (initialAppWrapperElement = element);
|
const syncAppWrapperElement2Sandbox = (element: HTMLElement | null) => (initialAppWrapperElement = element);
|
||||||
|
|
||||||
const parcelConfigGetter: ParcelConfigObjectGetter = (remountContainer = initialContainer) => {
|
const parcelConfigGetter: ParcelConfigObjectGetter = (remountContainer = initialContainer) => {
|
||||||
let appWrapperElement: HTMLElement | null = initialAppWrapperElement;
|
let appWrapperElement: HTMLElement | null;
|
||||||
const appWrapperGetter = getAppWrapperGetter(
|
let appWrapperGetter: ReturnType<typeof getAppWrapperGetter>;
|
||||||
appName,
|
|
||||||
appInstanceId,
|
|
||||||
!!legacyRender,
|
|
||||||
strictStyleIsolation,
|
|
||||||
scopedCSS,
|
|
||||||
() => appWrapperElement,
|
|
||||||
);
|
|
||||||
|
|
||||||
const parcelConfig: ParcelConfigObject = {
|
const parcelConfig: ParcelConfigObject = {
|
||||||
name: appInstanceId,
|
name: appInstanceId,
|
||||||
|
|
@ -371,6 +364,18 @@ export async function loadApp<T extends ObjectType>(
|
||||||
|
|
||||||
return undefined;
|
return undefined;
|
||||||
},
|
},
|
||||||
|
// initial wrapper element before app mount/remount
|
||||||
|
async () => {
|
||||||
|
appWrapperElement = initialAppWrapperElement;
|
||||||
|
appWrapperGetter = getAppWrapperGetter(
|
||||||
|
appName,
|
||||||
|
appInstanceId,
|
||||||
|
!!legacyRender,
|
||||||
|
strictStyleIsolation,
|
||||||
|
scopedCSS,
|
||||||
|
() => appWrapperElement,
|
||||||
|
);
|
||||||
|
},
|
||||||
// 添加 mount hook, 确保每次应用加载前容器 dom 结构已经设置完毕
|
// 添加 mount hook, 确保每次应用加载前容器 dom 结构已经设置完毕
|
||||||
async () => {
|
async () => {
|
||||||
const useNewContainer = remountContainer !== initialContainer;
|
const useNewContainer = remountContainer !== initialContainer;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user