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(); doc.close();
return new Promise((resolve) => { return new Promise((resolve) => {
const renderer = win.SimulatorRenderer || host.renderer; const renderer = win.SimulatorRenderer;
if (renderer) { if (renderer) {
return resolve(renderer); return resolve(renderer);
} }

View File

@ -850,7 +850,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
// filter with context // filter with context
return instances.filter((instance) => { 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 { 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 { globalContext, Editor, engineConfig, EngineOptions } from '@alilc/lowcode-editor-core';
import { import {
Designer, Designer,
@ -16,7 +16,7 @@ import {
import Outline, { OutlineBackupPane, getTreeMaster } from '@alilc/lowcode-plugin-outline-pane'; import Outline, { OutlineBackupPane, getTreeMaster } from '@alilc/lowcode-plugin-outline-pane';
import DesignerPlugin from '@alilc/lowcode-plugin-designer'; 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 { getLogger, isPlainObject } from '@alilc/lowcode-utils';
import './modules/live-editing'; import './modules/live-editing';
import utils from './modules/utils'; import utils from './modules/utils';
@ -184,7 +184,8 @@ engineConfig.set('isOpenSource', isOpenSource);
await plugins.register(defaultPanelRegistry); await plugins.register(defaultPanelRegistry);
})(); })();
let engineInited = false; // container which will host LowCodeEngine DOM
let engineContainer: HTMLElement;
// @ts-ignore webpack Define variable // @ts-ignore webpack Define variable
export const version = VERSION_PLACEHOLDER; export const version = VERSION_PLACEHOLDER;
engineConfig.set('ENGINE_VERSION', version); engineConfig.set('ENGINE_VERSION', version);
@ -193,23 +194,22 @@ export async function init(
options?: EngineOptions, options?: EngineOptions,
pluginPreference?: PluginPreference, pluginPreference?: PluginPreference,
) { ) {
if (engineInited) return; await destroy();
engineInited = true;
let engineOptions = null; let engineOptions = null;
let engineContainer = null;
if (isPlainObject(container)) { if (isPlainObject(container)) {
engineOptions = container; engineOptions = container;
engineContainer = document.createElement('div'); engineContainer = document.createElement('div');
engineContainer.id = 'engine';
document.body.appendChild(engineContainer); document.body.appendChild(engineContainer);
} else { } else {
engineOptions = options; engineOptions = options;
engineContainer = container; engineContainer = container;
if (!container) { if (!container) {
engineContainer = document.createElement('div'); engineContainer = document.createElement('div');
engineContainer.id = 'engine';
document.body.appendChild(engineContainer); document.body.appendChild(engineContainer);
} }
} }
engineContainer.id = 'engine';
engineConfig.setEngineOptions(engineOptions as any); engineConfig.setEngineOptions(engineOptions as any);
await plugins.init(pluginPreference as any); await plugins.init(pluginPreference as any);
@ -222,3 +222,17 @@ export async function init(
engineContainer, 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 { GlobalEvent } from '@alilc/lowcode-types';
import { SimulatorRendererContainer, DocumentInstance } from './renderer'; import { SimulatorRendererContainer, DocumentInstance } from './renderer';
import { host } from './host'; import { host } from './host';
import { isRendererDetached } from './utils/misc';
import './renderer.less'; import './renderer.less';
// patch cloneElement avoid lost keyProps // patch cloneElement avoid lost keyProps
@ -170,14 +170,12 @@ class Renderer extends Component<{
this.startTime = Date.now(); this.startTime = Date.now();
this.schemaChangedSymbol = false; this.schemaChangedSymbol = false;
if (!container.autoRender) return null; if (!container.autoRender || isRendererDetached()) return null;
return ( return (
<LowCodeRenderer <LowCodeRenderer
locale={locale} locale={locale}
messages={messages} messages={messages}
schema={documentInstance.schema} schema={documentInstance.schema}
deltaData={documentInstance.deltaData}
deltaMode={documentInstance.deltaMode}
components={container.components} components={container.components}
appHelper={container.context} appHelper={container.context}
designMode={designMode} designMode={designMode}

View File

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