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;
/** 沙箱是否在运行中 */
sandboxRunning: boolean;
/** latest set property */
latestSetProp?: PropertyKey | null;
/** 启动沙箱 */
active(): void;
/** 关闭沙箱 */

View File

@ -9,7 +9,7 @@ import { LifeCycles, ParcelConfigObject } from 'single-spa';
import getAddOns from './addons';
import { getMicroAppStateActions } from './globalState';
import { FrameworkConfiguration, FrameworkLifeCycles, HTMLContentRender, LifeCycleFn, LoadableApp } from './interfaces';
import { createSandbox, css } from './sandbox';
import { createSandboxContainer, css } from './sandbox';
import {
Deferred,
getContainer,
@ -53,6 +53,7 @@ async function validateSingularMode<T extends object>(
// @ts-ignore
const supportShadowDOM = document.head.attachShadow || document.head.createShadowRoot;
function createElement(
appContent: string,
strictStyleIsolation: boolean,
@ -199,11 +200,24 @@ function getRender(appName: string, appContent: string, legacyRender?: HTMLConte
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)) {
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') {
console.warn(
`[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>;
export type ParcelConfigObjectGetter = (remountContainer?: string | HTMLElement) => ParcelConfigObject;
export async function loadApp<T extends object>(
app: LoadableApp<T>,
configuration: FrameworkConfiguration = {},
@ -281,8 +296,9 @@ export async function loadApp<T extends object>(
let mountSandbox = () => Promise.resolve();
let unmountSandbox = () => Promise.resolve();
const useLooseSandbox = typeof sandbox === 'object' && !!sandbox.loose;
let sandboxContainer;
if (sandbox) {
const sandboxInstance = createSandbox(
sandboxContainer = createSandboxContainer(
appName,
// FIXME should use a strict sandbox logic while remount, see https://github.com/umijs/qiankun/issues/518
initialAppWrapperGetter,
@ -291,9 +307,9 @@ export async function loadApp<T extends object>(
excludeAssetFilter,
);
// 用沙箱的代理对象作为接下来使用的全局对象
global = sandboxInstance.proxy as typeof window;
mountSandbox = sandboxInstance.mount;
unmountSandbox = sandboxInstance.unmount;
global = sandboxContainer.instance.proxy as typeof window;
mountSandbox = sandboxContainer.mount;
unmountSandbox = sandboxContainer.unmount;
}
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
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 {
onGlobalStateChange,

View File

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

View File

@ -41,6 +41,8 @@ export default class SingularProxySandbox implements SandBox {
sandboxRunning = true;
latestSetProp: PropertyKey | null = null;
active() {
if (!this.sandboxRunning) {
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
(rawWindow as any)[p] = value;
self.latestSetProp = p;
return true;
}

View File

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