record latest set property to use to fallback in some incompatible scenario (#1056)

This commit is contained in:
Kuitos 2020-11-06 19:46:17 +08:00 committed by GitHub
parent 3c40e1b9ad
commit 44726a22b6
5 changed files with 40 additions and 9 deletions

View File

@ -115,6 +115,8 @@ export interface SandBox {
proxy: WindowProxy; proxy: WindowProxy;
/** 沙箱是否在运行中 */ /** 沙箱是否在运行中 */
sandboxRunning: boolean; sandboxRunning: boolean;
/** latest set property */
latestSetProp?: PropertyKey | null;
/** 启动沙箱 */ /** 启动沙箱 */
active(): void; active(): void;
/** 关闭沙箱 */ /** 关闭沙箱 */

View File

@ -9,7 +9,7 @@ import { LifeCycles, ParcelConfigObject } from 'single-spa';
import getAddOns from './addons'; import getAddOns from './addons';
import { getMicroAppStateActions } from './globalState'; import { getMicroAppStateActions } from './globalState';
import { FrameworkConfiguration, FrameworkLifeCycles, HTMLContentRender, LifeCycleFn, LoadableApp } from './interfaces'; import { FrameworkConfiguration, FrameworkLifeCycles, HTMLContentRender, LifeCycleFn, LoadableApp } from './interfaces';
import { createSandbox, css } from './sandbox'; import { createSandboxContainer, css } from './sandbox';
import { import {
Deferred, Deferred,
getContainer, getContainer,
@ -53,6 +53,7 @@ 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( function createElement(
appContent: string, appContent: string,
strictStyleIsolation: boolean, strictStyleIsolation: boolean,
@ -199,11 +200,24 @@ function getRender(appName: string, appContent: string, legacyRender?: HTMLConte
return render; return render;
} }
function getLifecyclesFromExports(scriptExports: LifeCycles<any>, appName: string, global: WindowProxy) { function getLifecyclesFromExports(
scriptExports: LifeCycles<any>,
appName: string,
global: WindowProxy,
globalLatestSetProp?: PropertyKey | null,
) {
if (validateExportLifecycle(scriptExports)) { if (validateExportLifecycle(scriptExports)) {
return scriptExports; return scriptExports;
} }
// fallback to sandbox latest set property if it had
if (globalLatestSetProp) {
const lifecycles = (<any>global)[globalLatestSetProp];
if (validateExportLifecycle(lifecycles)) {
return lifecycles;
}
}
if (process.env.NODE_ENV === 'development') { if (process.env.NODE_ENV === 'development') {
console.warn( console.warn(
`[qiankun] lifecycle not found from ${appName} entry exports, fallback to get from window['${appName}']`, `[qiankun] lifecycle not found from ${appName} entry exports, fallback to get from window['${appName}']`,
@ -223,6 +237,7 @@ function getLifecyclesFromExports(scriptExports: LifeCycles<any>, appName: strin
let prevAppUnmountedDeferred: Deferred<void>; let prevAppUnmountedDeferred: Deferred<void>;
export type ParcelConfigObjectGetter = (remountContainer?: string | HTMLElement) => ParcelConfigObject; export type ParcelConfigObjectGetter = (remountContainer?: string | HTMLElement) => ParcelConfigObject;
export async function loadApp<T extends object>( export async function loadApp<T extends object>(
app: LoadableApp<T>, app: LoadableApp<T>,
configuration: FrameworkConfiguration = {}, configuration: FrameworkConfiguration = {},
@ -281,8 +296,9 @@ export async function loadApp<T extends object>(
let mountSandbox = () => Promise.resolve(); let mountSandbox = () => Promise.resolve();
let unmountSandbox = () => Promise.resolve(); let unmountSandbox = () => Promise.resolve();
const useLooseSandbox = typeof sandbox === 'object' && !!sandbox.loose; const useLooseSandbox = typeof sandbox === 'object' && !!sandbox.loose;
let sandboxContainer;
if (sandbox) { if (sandbox) {
const sandboxInstance = createSandbox( sandboxContainer = createSandboxContainer(
appName, appName,
// FIXME should use a strict sandbox logic while remount, see https://github.com/umijs/qiankun/issues/518 // FIXME should use a strict sandbox logic while remount, see https://github.com/umijs/qiankun/issues/518
initialAppWrapperGetter, initialAppWrapperGetter,
@ -291,9 +307,9 @@ export async function loadApp<T extends object>(
excludeAssetFilter, excludeAssetFilter,
); );
// 用沙箱的代理对象作为接下来使用的全局对象 // 用沙箱的代理对象作为接下来使用的全局对象
global = sandboxInstance.proxy as typeof window; global = sandboxContainer.instance.proxy as typeof window;
mountSandbox = sandboxInstance.mount; mountSandbox = sandboxContainer.mount;
unmountSandbox = sandboxInstance.unmount; unmountSandbox = sandboxContainer.unmount;
} }
const { beforeUnmount = [], afterUnmount = [], afterMount = [], beforeMount = [], beforeLoad = [] } = mergeWith( const { beforeUnmount = [], afterUnmount = [], afterMount = [], beforeMount = [], beforeLoad = [] } = mergeWith(
@ -307,7 +323,12 @@ export async function loadApp<T extends object>(
// get the lifecycle hooks from module exports // get the lifecycle hooks from module exports
const scriptExports: any = await execScripts(global, !useLooseSandbox); const scriptExports: any = await execScripts(global, !useLooseSandbox);
const { bootstrap, mount, unmount, update } = getLifecyclesFromExports(scriptExports, appName, global); const { bootstrap, mount, unmount, update } = getLifecyclesFromExports(
scriptExports,
appName,
global,
sandboxContainer?.instance?.latestSetProp,
);
const { const {
onGlobalStateChange, onGlobalStateChange,

View File

@ -28,7 +28,7 @@ export { css } from './patchers';
* @param useLooseSandbox * @param useLooseSandbox
* @param excludeAssetFilter * @param excludeAssetFilter
*/ */
export function createSandbox( export function createSandboxContainer(
appName: string, appName: string,
elementGetter: () => HTMLElement | ShadowRoot, elementGetter: () => HTMLElement | ShadowRoot,
scopedCSS: boolean, scopedCSS: boolean,
@ -50,7 +50,7 @@ export function createSandbox(
let sideEffectsRebuilders: Rebuilder[] = []; let sideEffectsRebuilders: Rebuilder[] = [];
return { return {
proxy: sandbox.proxy, instance: sandbox,
/** /**
* mount * mount

View File

@ -41,6 +41,8 @@ export default class SingularProxySandbox implements SandBox {
sandboxRunning = true; sandboxRunning = true;
latestSetProp: PropertyKey | null = null;
active() { active() {
if (!this.sandboxRunning) { if (!this.sandboxRunning) {
this.currentUpdatedPropsValueMap.forEach((v, p) => setWindowProp(p, v)); this.currentUpdatedPropsValueMap.forEach((v, p) => setWindowProp(p, v));
@ -90,6 +92,8 @@ export default class SingularProxySandbox implements SandBox {
// eslint-disable-next-line no-param-reassign // eslint-disable-next-line no-param-reassign
(rawWindow as any)[p] = value; (rawWindow as any)[p] = value;
self.latestSetProp = p;
return true; return true;
} }

View File

@ -136,6 +136,8 @@ export default class ProxySandbox implements SandBox {
sandboxRunning = true; sandboxRunning = true;
latestSetProp: PropertyKey | null = null;
active() { active() {
if (!this.sandboxRunning) activeSandboxCount++; if (!this.sandboxRunning) activeSandboxCount++;
this.sandboxRunning = true; this.sandboxRunning = true;
@ -199,6 +201,8 @@ export default class ProxySandbox implements SandBox {
updatedValueSet.add(p); updatedValueSet.add(p);
self.latestSetProp = p;
return true; return true;
} }