🐛 compute container xpath at beginning to keep it consist around app running (#1725)
This commit is contained in:
parent
c4b604228a
commit
cbad8c8d7d
59
src/apis.ts
59
src/apis.ts
|
|
@ -1,12 +1,18 @@
|
||||||
import { noop } from 'lodash';
|
import { noop } from 'lodash';
|
||||||
import type { ParcelConfigObject } from 'single-spa';
|
import type { ParcelConfigObject } from 'single-spa';
|
||||||
import { mountRootParcel, registerApplication, start as startSingleSpa } from 'single-spa';
|
import { mountRootParcel, registerApplication, start as startSingleSpa } from 'single-spa';
|
||||||
import type { ObjectType } from './interfaces';
|
import type {
|
||||||
import type { FrameworkConfiguration, FrameworkLifeCycles, LoadableApp, MicroApp, RegistrableApp } from './interfaces';
|
FrameworkConfiguration,
|
||||||
|
FrameworkLifeCycles,
|
||||||
|
LoadableApp,
|
||||||
|
MicroApp,
|
||||||
|
ObjectType,
|
||||||
|
RegistrableApp,
|
||||||
|
} from './interfaces';
|
||||||
import type { ParcelConfigObjectGetter } from './loader';
|
import type { ParcelConfigObjectGetter } from './loader';
|
||||||
import { loadApp } from './loader';
|
import { loadApp } from './loader';
|
||||||
import { doPrefetchStrategy } from './prefetch';
|
import { doPrefetchStrategy } from './prefetch';
|
||||||
import { Deferred, getContainer, getXPathForElement, toArray } from './utils';
|
import { Deferred, getContainerXPath, toArray } from './utils';
|
||||||
|
|
||||||
let microApps: Array<RegistrableApp<Record<string, unknown>>> = [];
|
let microApps: Array<RegistrableApp<Record<string, unknown>>> = [];
|
||||||
|
|
||||||
|
|
@ -80,24 +86,18 @@ export function loadMicroApp<T extends ObjectType>(
|
||||||
): MicroApp {
|
): MicroApp {
|
||||||
const { props, name } = app;
|
const { props, name } = app;
|
||||||
|
|
||||||
const getContainerXpath = (container: string | HTMLElement): string | void => {
|
const container = 'container' in app ? app.container : undefined;
|
||||||
const containerElement = getContainer(container);
|
// Must compute the container xpath at beginning to keep it consist around app running
|
||||||
if (containerElement) {
|
// If we compute it every time, the container dom structure most probably been changed and result in a different xpath value
|
||||||
return getXPathForElement(containerElement, document);
|
const containerXPath = getContainerXPath(container);
|
||||||
}
|
const appContainerXPathKey = `${name}-${containerXPath}`;
|
||||||
|
|
||||||
return undefined;
|
|
||||||
};
|
|
||||||
|
|
||||||
let microApp: MicroApp;
|
let microApp: MicroApp;
|
||||||
const wrapParcelConfigForRemount = (config: ParcelConfigObject): ParcelConfigObject => {
|
const wrapParcelConfigForRemount = (config: ParcelConfigObject): ParcelConfigObject => {
|
||||||
const container = 'container' in app ? app.container : undefined;
|
|
||||||
|
|
||||||
let microAppConfig = config;
|
let microAppConfig = config;
|
||||||
if (container) {
|
if (container) {
|
||||||
const xpath = getContainerXpath(container);
|
if (containerXPath) {
|
||||||
if (xpath) {
|
const containerMicroApps = containerMicroAppsMap.get(appContainerXPathKey);
|
||||||
const containerMicroApps = containerMicroAppsMap.get(`${name}-${xpath}`);
|
|
||||||
if (containerMicroApps?.length) {
|
if (containerMicroApps?.length) {
|
||||||
const mount = [
|
const mount = [
|
||||||
async () => {
|
async () => {
|
||||||
|
|
@ -137,7 +137,6 @@ export function loadMicroApp<T extends ObjectType>(
|
||||||
configuration ?? { ...frameworkConfiguration, singular: false },
|
configuration ?? { ...frameworkConfiguration, singular: false },
|
||||||
);
|
);
|
||||||
const { $$cacheLifecycleByAppName } = userConfiguration;
|
const { $$cacheLifecycleByAppName } = userConfiguration;
|
||||||
const container = 'container' in app ? app.container : undefined;
|
|
||||||
|
|
||||||
if (container) {
|
if (container) {
|
||||||
// using appName as cache for internal experimental scenario
|
// using appName as cache for internal experimental scenario
|
||||||
|
|
@ -146,9 +145,8 @@ export function loadMicroApp<T extends ObjectType>(
|
||||||
if (parcelConfigGetterPromise) return wrapParcelConfigForRemount((await parcelConfigGetterPromise)(container));
|
if (parcelConfigGetterPromise) return wrapParcelConfigForRemount((await parcelConfigGetterPromise)(container));
|
||||||
}
|
}
|
||||||
|
|
||||||
const xpath = getContainerXpath(container);
|
if (containerXPath) {
|
||||||
if (xpath) {
|
const parcelConfigGetterPromise = appConfigPromiseGetterMap.get(appContainerXPathKey);
|
||||||
const parcelConfigGetterPromise = appConfigPromiseGetterMap.get(`${name}-${xpath}`);
|
|
||||||
if (parcelConfigGetterPromise) return wrapParcelConfigForRemount((await parcelConfigGetterPromise)(container));
|
if (parcelConfigGetterPromise) return wrapParcelConfigForRemount((await parcelConfigGetterPromise)(container));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -158,10 +156,7 @@ export function loadMicroApp<T extends ObjectType>(
|
||||||
if (container) {
|
if (container) {
|
||||||
if ($$cacheLifecycleByAppName) {
|
if ($$cacheLifecycleByAppName) {
|
||||||
appConfigPromiseGetterMap.set(name, parcelConfigObjectGetterPromise);
|
appConfigPromiseGetterMap.set(name, parcelConfigObjectGetterPromise);
|
||||||
} else {
|
} else if (containerXPath) appConfigPromiseGetterMap.set(appContainerXPathKey, parcelConfigObjectGetterPromise);
|
||||||
const xpath = getContainerXpath(container);
|
|
||||||
if (xpath) appConfigPromiseGetterMap.set(`${name}-${xpath}`, parcelConfigObjectGetterPromise);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (await parcelConfigObjectGetterPromise)(container);
|
return (await parcelConfigObjectGetterPromise)(container);
|
||||||
|
|
@ -177,18 +172,14 @@ export function loadMicroApp<T extends ObjectType>(
|
||||||
|
|
||||||
microApp = 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) {
|
if (container) {
|
||||||
const xpath = getContainerXpath(container);
|
if (containerXPath) {
|
||||||
if (xpath) {
|
// Store the microApps which they mounted on the same container
|
||||||
const key = `${name}-${xpath}`;
|
const microAppsRef = containerMicroAppsMap.get(appContainerXPathKey) || [];
|
||||||
|
|
||||||
const microAppsRef = containerMicroAppsMap.get(key) || [];
|
|
||||||
microAppsRef.push(microApp);
|
microAppsRef.push(microApp);
|
||||||
containerMicroAppsMap.set(key, microAppsRef);
|
containerMicroAppsMap.set(appContainerXPathKey, microAppsRef);
|
||||||
|
|
||||||
const cleanApp = () => {
|
const cleanup = () => {
|
||||||
const index = microAppsRef.indexOf(microApp);
|
const index = microAppsRef.indexOf(microApp);
|
||||||
microAppsRef.splice(index, 1);
|
microAppsRef.splice(index, 1);
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
|
@ -196,7 +187,7 @@ export function loadMicroApp<T extends ObjectType>(
|
||||||
};
|
};
|
||||||
|
|
||||||
// gc after unmount
|
// gc after unmount
|
||||||
microApp.unmountPromise.then(cleanApp).catch(cleanApp);
|
microApp.unmountPromise.then(cleanup).catch(cleanup);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
11
src/utils.ts
11
src/utils.ts
|
|
@ -215,3 +215,14 @@ export function getXPathForElement(el: Node, document: Document): string | void
|
||||||
export function getContainer(container: string | HTMLElement): HTMLElement | null {
|
export function getContainer(container: string | HTMLElement): HTMLElement | null {
|
||||||
return typeof container === 'string' ? document.querySelector(container) : container;
|
return typeof container === 'string' ? document.querySelector(container) : container;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getContainerXPath(container?: string | HTMLElement): string | void {
|
||||||
|
if (container) {
|
||||||
|
const containerElement = getContainer(container);
|
||||||
|
if (containerElement) {
|
||||||
|
return getXPathForElement(containerElement, document);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user