feat: support SPA mode

This commit is contained in:
LeoYuan 袁力皓 2022-09-19 20:31:33 +08:00 committed by 刘菊萍(絮黎)
parent 0bcd9ff782
commit 1f9150e4b2
6 changed files with 38 additions and 35 deletions

View File

@ -98,7 +98,7 @@ export function createSimulator(
doc.close();
return new Promise((resolve) => {
const renderer = win.SimulatorRenderer || host.renderer;
const renderer = win.SimulatorRenderer;
if (renderer) {
return resolve(renderer);
}

View File

@ -850,7 +850,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
// filter with context
return instances.filter((instance) => {
return this.getClosestNodeInstance(instance, context.nodeId)?.instance === context.instance;
return this.getClosestNodeInstance(instance, context?.nodeId)?.instance === context.instance;
});
}

View File

@ -1,5 +1,5 @@
import { createElement } from 'react';
import { render } from 'react-dom';
import { render, unmountComponentAtNode } from 'react-dom';
import { globalContext, Editor, engineConfig, EngineOptions } from '@alilc/lowcode-editor-core';
import {
Designer,
@ -16,7 +16,7 @@ import {
import Outline, { OutlineBackupPane, getTreeMaster } from '@alilc/lowcode-plugin-outline-pane';
import DesignerPlugin from '@alilc/lowcode-plugin-designer';
import { Hotkey, Project, Skeleton, Setters, Material, Event } from '@alilc/lowcode-shell';
import { Hotkey, Project, Skeleton, Setters, Material, Event, DocumentModel } from '@alilc/lowcode-shell';
import { getLogger, isPlainObject } from '@alilc/lowcode-utils';
import './modules/live-editing';
import utils from './modules/utils';
@ -184,7 +184,8 @@ engineConfig.set('isOpenSource', isOpenSource);
await plugins.register(defaultPanelRegistry);
})();
let engineInited = false;
// container which will host LowCodeEngine DOM
let engineContainer: HTMLElement;
// @ts-ignore webpack Define variable
export const version = VERSION_PLACEHOLDER;
engineConfig.set('ENGINE_VERSION', version);
@ -193,23 +194,22 @@ export async function init(
options?: EngineOptions,
pluginPreference?: PluginPreference,
) {
if (engineInited) return;
engineInited = true;
await destroy();
let engineOptions = null;
let engineContainer = null;
if (isPlainObject(container)) {
engineOptions = container;
engineContainer = document.createElement('div');
engineContainer.id = 'engine';
document.body.appendChild(engineContainer);
} else {
engineOptions = options;
engineContainer = container;
if (!container) {
engineContainer = document.createElement('div');
engineContainer.id = 'engine';
document.body.appendChild(engineContainer);
}
}
engineContainer.id = 'engine';
engineConfig.setEngineOptions(engineOptions as any);
await plugins.init(pluginPreference as any);
@ -222,3 +222,17 @@ export async function init(
engineContainer,
);
}
export async function destroy() {
// remove all documents
const { documents } = project;
if (Array.isArray(documents) && documents.length > 0) {
documents.forEach(((doc: DocumentModel) => project.removeDocument(doc)));
}
// TODO: delete plugins except for core plugins
// unmount DOM container, this will trigger React componentWillUnmount lifeCycle,
// so necessary cleanups will be done.
engineContainer && unmountComponentAtNode(engineContainer);
}

View File

@ -8,7 +8,7 @@ import { getClosestNode, isFromVC, isReactComponent } from '@alilc/lowcode-utils
import { GlobalEvent } from '@alilc/lowcode-types';
import { SimulatorRendererContainer, DocumentInstance } from './renderer';
import { host } from './host';
import { isRendererDetached } from './utils/misc';
import './renderer.less';
// patch cloneElement avoid lost keyProps
@ -170,14 +170,12 @@ class Renderer extends Component<{
this.startTime = Date.now();
this.schemaChangedSymbol = false;
if (!container.autoRender) return null;
if (!container.autoRender || isRendererDetached()) return null;
return (
<LowCodeRenderer
locale={locale}
messages={messages}
schema={documentInstance.schema}
deltaData={documentInstance.deltaData}
deltaMode={documentInstance.deltaMode}
components={container.components}
appHelper={container.context}
designMode={designMode}

View File

@ -51,24 +51,6 @@ export class DocumentInstance {
return this._components;
}
/**
*
*/
@obx.ref private _deltaData: any = {};
@computed get deltaData(): any {
return this._deltaData;
}
/**
* 使
*/
@obx.ref private _deltaMode: boolean = false;
@computed get deltaMode(): boolean {
return this._deltaMode;
}
// context from: utils、constants、history、location、match
@obx.ref private _appContext = {};
@ -116,7 +98,7 @@ export class DocumentInstance {
return this.document.id;
}
private unmountIntance(id: string, instance: ReactInstance) {
private unmountInstance(id: string, instance: ReactInstance) {
const instances = this.instancesMap.get(id);
if (instances) {
const i = instances.indexOf(instance);
@ -144,11 +126,11 @@ export class DocumentInstance {
}
return;
}
const unmountIntance = this.unmountIntance.bind(this);
const unmountInstance = this.unmountInstance.bind(this);
const origId = (instance as any)[SYMBOL_VNID];
if (origId && origId !== id) {
// 另外一个节点的 instance 在此被复用了,需要从原来地方卸载
unmountIntance(origId, instance);
unmountInstance(origId, instance);
}
if (isElement(instance)) {
cacheReactKey(instance);
@ -160,7 +142,7 @@ export class DocumentInstance {
}
// hack! delete instance from map
const newUnmount = function (this: any) {
unmountIntance(id, instance);
unmountInstance(id, instance);
origUnmount && origUnmount.call(this);
};
(newUnmount as any).origUnmount = origUnmount;

View File

@ -24,3 +24,12 @@ export function getProjectUtils(librayMap: LibrayMap, utilsMetadata: UtilsMetada
});
}
}
/**
* judges if current simulator renderer deteched or not
* @returns detached or not
*/
export function isRendererDetached() {
// if current iframe detached from host document, the `window.parent` will be undefined.
return !window.parent;
}