From b8571b2346c365cadfb093a6a1acbf3e06b3e089 Mon Sep 17 00:00:00 2001 From: Kuitos Date: Wed, 8 Dec 2021 20:36:42 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20use=20new=20unique=20instance=20nam?= =?UTF-8?q?e=20generator=20(#1859)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/__tests__/utils.test.ts | 2 +- src/loader.ts | 42 ++++++++++++++++++------------------- src/utils.ts | 31 +++++++++++++++++++++++---- 3 files changed, 48 insertions(+), 27 deletions(-) diff --git a/src/__tests__/utils.test.ts b/src/__tests__/utils.test.ts index 7c92813..c256055 100644 --- a/src/__tests__/utils.test.ts +++ b/src/__tests__/utils.test.ts @@ -23,7 +23,7 @@ test('should wrap the id [2]', () => { test('should wrap string with div', () => { const tpl = 'qiankun'; - const factory = getDefaultTplWrapper('react16', 'react16'); + const factory = getDefaultTplWrapper('react16'); const ret = factory(tpl); diff --git a/src/loader.ts b/src/loader.ts index 0363017..c519c5f 100644 --- a/src/loader.ts +++ b/src/loader.ts @@ -20,13 +20,14 @@ import type { import { createSandboxContainer, css } from './sandbox'; import { Deferred, + getAppInstanceName, getContainer, getDefaultTplWrapper, getWrapperId, isEnableScopedCSS, + performanceGetEntriesByName, performanceMark, performanceMeasure, - performanceGetEntriesByName, toArray, validateExportLifecycle, } from './utils'; @@ -111,7 +112,6 @@ function createElement( /** generate app wrapper dom getter */ function getAppWrapperGetter( appName: string, - appInstanceId: string, useLegacyRender: boolean, strictStyleIsolation: boolean, scopedCSS: boolean, @@ -122,13 +122,13 @@ function getAppWrapperGetter( if (strictStyleIsolation) throw new QiankunError('strictStyleIsolation can not be used with legacy render!'); if (scopedCSS) throw new QiankunError('experimentalStyleIsolation can not be used with legacy render!'); - const appWrapper = document.getElementById(getWrapperId(appInstanceId)); - assertElementExist(appWrapper, `Wrapper element for ${appName} with instance ${appInstanceId} is not existed!`); + const appWrapper = document.getElementById(getWrapperId(appName)); + assertElementExist(appWrapper, `Wrapper element for ${appName} is not existed!`); return appWrapper!; } const element = elementGetter(); - assertElementExist(element, `Wrapper element for ${appName} with instance ${appInstanceId} is not existed!`); + assertElementExist(element, `Wrapper element for ${appName} is not existed!`); if (strictStyleIsolation && supportShadowDOM) { return element!.shadowRoot!; @@ -246,10 +246,10 @@ export async function loadApp( configuration: FrameworkConfiguration = {}, lifeCycles?: FrameworkLifeCycles, ): Promise { - const { entry, name: appName } = app; - const appInstanceId = `${appName}_${+new Date()}_${Math.floor(Math.random() * 1000)}`; + const { entry } = app; + const appInstanceName = getAppInstanceName(app.name); - const markName = `[qiankun] App ${appInstanceId} Loading`; + const markName = `[qiankun] App ${appInstanceName} Loading`; if (process.env.NODE_ENV === 'development') { performanceMark(markName); } @@ -272,7 +272,7 @@ export async function loadApp( await (prevAppUnmountedDeferred && prevAppUnmountedDeferred.promise); } - const appContent = getDefaultTplWrapper(appInstanceId, appName)(template); + const appContent = getDefaultTplWrapper(appInstanceName)(template); const strictStyleIsolation = typeof sandbox === 'object' && !!sandbox.strictStyleIsolation; @@ -287,21 +287,20 @@ export async function loadApp( appContent, strictStyleIsolation, scopedCSS, - appName, + appInstanceName, ); const initialContainer = 'container' in app ? app.container : undefined; const legacyRender = 'render' in app ? app.render : undefined; - const render = getRender(appName, appContent, legacyRender); + const render = getRender(appInstanceName, appContent, legacyRender); // 第一次加载设置应用可见区域 dom 结构 // 确保每次应用加载前容器 dom 结构已经设置完毕 render({ element: initialAppWrapperElement, loading: true, container: initialContainer }, 'loading'); const initialAppWrapperGetter = getAppWrapperGetter( - appName, - appInstanceId, + appInstanceName, !!legacyRender, strictStyleIsolation, scopedCSS, @@ -315,7 +314,7 @@ export async function loadApp( let sandboxContainer; if (sandbox) { sandboxContainer = createSandboxContainer( - appName, + appInstanceName, // FIXME should use a strict sandbox logic while remount, see https://github.com/umijs/qiankun/issues/518 initialAppWrapperGetter, scopedCSS, @@ -343,13 +342,13 @@ export async function loadApp( const scriptExports: any = await execScripts(global, sandbox && !useLooseSandbox); const { bootstrap, mount, unmount, update } = getLifecyclesFromExports( scriptExports, - appName, + appInstanceName, global, sandboxContainer?.instance?.latestSetProp, ); const { onGlobalStateChange, setGlobalState, offGlobalStateChange }: Record = - getMicroAppStateActions(appInstanceId); + getMicroAppStateActions(appInstanceName); // FIXME temporary way const syncAppWrapperElement2Sandbox = (element: HTMLElement | null) => (initialAppWrapperElement = element); @@ -359,7 +358,7 @@ export async function loadApp( let appWrapperGetter: ReturnType; const parcelConfig: ParcelConfigObject = { - name: appInstanceId, + name: appInstanceName, bootstrap, mount: [ async () => { @@ -382,8 +381,7 @@ export async function loadApp( async () => { appWrapperElement = initialAppWrapperElement; appWrapperGetter = getAppWrapperGetter( - appName, - appInstanceId, + appInstanceName, !!legacyRender, strictStyleIsolation, scopedCSS, @@ -396,7 +394,7 @@ export async function loadApp( if (useNewContainer || !appWrapperElement) { // element will be destroyed after unmounted, we need to recreate it if it not exist // or we try to remount into a new container - appWrapperElement = createElement(appContent, strictStyleIsolation, scopedCSS, appName); + appWrapperElement = createElement(appContent, strictStyleIsolation, scopedCSS, appInstanceName); syncAppWrapperElement2Sandbox(appWrapperElement); } @@ -417,7 +415,7 @@ export async function loadApp( }, async () => { if (process.env.NODE_ENV === 'development') { - const measureName = `[qiankun] App ${appInstanceId} Loading Consuming`; + const measureName = `[qiankun] App ${appInstanceName} Loading Consuming`; performanceMeasure(measureName, markName); } }, @@ -429,7 +427,7 @@ export async function loadApp( async () => execHooksChain(toArray(afterUnmount), app, global), async () => { render({ element: null, loading: false, container: remountContainer }, 'unmounted'); - offGlobalStateChange(appInstanceId); + offGlobalStateChange(appInstanceName); // for gc appWrapperElement = null; syncAppWrapperElement2Sandbox(appWrapperElement); diff --git a/src/utils.ts b/src/utils.ts index 3926718..47f3504 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -101,16 +101,39 @@ export function isBoundedFunction(fn: CallableFunction) { return bounded; } -export function getDefaultTplWrapper(id: string, name: string) { - return (tpl: string) => `
${tpl}
`; +export function getDefaultTplWrapper(name: string) { + return (tpl: string) => `
${tpl}
`; } -export function getWrapperId(id: string) { - return `__qiankun_microapp_wrapper_for_${snakeCase(id)}__`; +export function getWrapperId(name: string) { + return `__qiankun_microapp_wrapper_for_${snakeCase(name)}__`; } export const nativeGlobal = new Function('return this')(); +/** + * get app instance name with the auto-increment approach + * @param appName + */ +export const getAppInstanceName = (appName: string): string => { + if (typeof nativeGlobal.__app_instance_name_map__?.[appName] === undefined) { + const prevAppsCount = nativeGlobal.__app_instance_name_map__ || {}; + Object.defineProperty(nativeGlobal, '__app_instance_name_map__', { + enumerable: false, + writable: true, + value: { + ...prevAppsCount, + [appName]: 0, + }, + }); + + return appName; + } + + nativeGlobal.__app_instance_name_map__[appName]++; + return `${appName}_${nativeGlobal.__app_instance_name_map__[appName]}`; +}; + /** 校验子应用导出的 生命周期 对象是否正确 */ export function validateExportLifecycle(exports: any) { const { bootstrap, mount, unmount } = exports ?? {};