refactor: 优化初始创建 doc 时触发响应式获取 schema 的次数

This commit is contained in:
lihao.ylh 2021-09-17 20:48:01 +08:00
parent f4e07fe290
commit 3b645d270d
9 changed files with 172 additions and 17 deletions

View File

@ -6,7 +6,7 @@ module.exports = {
// // '^.+\\.(ts|tsx)$': 'ts-jest', // // '^.+\\.(ts|tsx)$': 'ts-jest',
// // '^.+\\.(js|jsx)$': 'babel-jest', // // '^.+\\.(js|jsx)$': 'babel-jest',
// }, // },
// testMatch: ['**/prop.test.ts'], // testMatch: ['**/builtin-hotkey.test.ts'],
// testMatch: ['(/tests?/.*(test))\\.[jt]s$'], // testMatch: ['(/tests?/.*(test))\\.[jt]s$'],
transformIgnorePatterns: [ transformIgnorePatterns: [
`/node_modules/(?!${esModules})/`, `/node_modules/(?!${esModules})/`,

View File

@ -1,5 +1,5 @@
import { EventEmitter } from 'events'; import { EventEmitter } from 'events';
import { autorun, Reaction, untracked, globalContext, Editor } from '@ali/lowcode-editor-core'; import { autorun, reaction, mobx, untracked, globalContext, Editor } from '@ali/lowcode-editor-core';
import { NodeSchema } from '@ali/lowcode-types'; import { NodeSchema } from '@ali/lowcode-types';
// TODO: cache to localStorage // TODO: cache to localStorage
@ -37,17 +37,12 @@ export class History {
this.session = new Session(0, null, this.timeGap); this.session = new Session(0, null, this.timeGap);
this.records = [this.session]; this.records = [this.session];
autorun(() => { reaction(() => {
return logger();
}, (data) => {
if (this.asleep) return; if (this.asleep) return;
const data = logger();
untracked(() => { untracked(() => {
const log = currentSerialization.serialize(data); const log = currentSerialization.serialize(data);
if (this.session.cursor === 0 && this.session.isActive()) {
// first log
this.session.log(log);
this.session.end();
} else if (this.session) {
if (this.session.isActive()) { if (this.session.isActive()) {
this.session.log(log); this.session.log(log);
} else { } else {
@ -62,9 +57,9 @@ export class History {
this.emitter.emit('statechange', currentState); this.emitter.emit('statechange', currentState);
} }
} }
} // }
}); });
}); }, { fireImmediately: true });
} }
get hotData() { get hotData() {

View File

@ -122,7 +122,7 @@ export class ModalNodesManager {
} }
private setNodes() { private setNodes() {
const nodes = getModalNodes(this.page.getRoot()); const nodes = getModalNodes(this.page.getRoot()!);
this.modalNodes = nodes; this.modalNodes = nodes;
this.modalNodes.forEach((node: Node) => { this.modalNodes.forEach((node: Node) => {
this.addNodeEvent(node); this.addNodeEvent(node);

View File

@ -179,6 +179,8 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
this.setupAutoruns(); this.setupAutoruns();
} }
this.initBuiltinProps();
this.isInited = true; this.isInited = true;
this.emitter = new EventEmitter(); this.emitter = new EventEmitter();
} }
@ -191,6 +193,18 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
return this._settingEntry; return this._settingEntry;
} }
/**
* prop reaction
*/
private initBuiltinProps() {
this.props.has(getConvertedExtraKey('hidden')) || this.props.add(false, getConvertedExtraKey('hidden'));
this.props.has(getConvertedExtraKey('title')) || this.props.add('', getConvertedExtraKey('title'));
this.props.has(getConvertedExtraKey('isLocked')) || this.props.add(false, getConvertedExtraKey('isLocked'));
this.props.has(getConvertedExtraKey('condition')) || this.props.add(true, getConvertedExtraKey('condition'));
this.props.has(getConvertedExtraKey('conditionGroup')) || this.props.add('', getConvertedExtraKey('conditionGroup'));
this.props.has(getConvertedExtraKey('loop')) || this.props.add(undefined, getConvertedExtraKey('loop'));
}
private initProps(props: any): any { private initProps(props: any): any {
return this.document.designer.transformProps(props, this, TransformStage.Init); return this.document.designer.transformProps(props, this, TransformStage.Init);
} }

View File

@ -102,6 +102,9 @@ describe('快捷键测试', () => {
const firstButtonNode = designer.currentDocument?.getNode('node_k1ow3cbn')!; const firstButtonNode = designer.currentDocument?.getNode('node_k1ow3cbn')!;
let secondButtonNode = designer.currentDocument?.getNode('node_k1ow3cbp')!; let secondButtonNode = designer.currentDocument?.getNode('node_k1ow3cbp')!;
// 等待第一个 session 结束
await new Promise(resolve => setTimeout(resolve, 1000));
firstButtonNode.remove(); firstButtonNode.remove();
expect(secondButtonNode.getParent()?.children.size).toBe(1); expect(secondButtonNode.getParent()?.children.size).toBe(1);
@ -119,6 +122,9 @@ describe('快捷键测试', () => {
const firstButtonNode = designer.currentDocument?.getNode('node_k1ow3cbn')!; const firstButtonNode = designer.currentDocument?.getNode('node_k1ow3cbn')!;
let secondButtonNode = designer.currentDocument?.getNode('node_k1ow3cbp')!; let secondButtonNode = designer.currentDocument?.getNode('node_k1ow3cbp')!;
// 等待第一个 session 结束
await new Promise(resolve => setTimeout(resolve, 1000));
firstButtonNode.remove(); firstButtonNode.remove();
expect(secondButtonNode.getParent()?.children.size).toBe(1); expect(secondButtonNode.getParent()?.children.size).toBe(1);

View File

@ -68,7 +68,11 @@ Object {
Object { Object {
"componentName": "PageHeader", "componentName": "PageHeader",
"condition": true, "condition": true,
"conditionGroup": "",
"hidden": false,
"id": "node_k1ow3cbd", "id": "node_k1ow3cbd",
"isLocked": false,
"loop": undefined,
"props": Object { "props": Object {
"__slot__action": false, "__slot__action": false,
"__slot__content": false, "__slot__content": false,
@ -108,12 +112,18 @@ Object {
], ],
}, },
}, },
"title": "",
}, },
], ],
"componentName": "RootHeader", "componentName": "RootHeader",
"condition": true, "condition": true,
"conditionGroup": "",
"hidden": false,
"id": "node_k1ow3cba", "id": "node_k1ow3cba",
"isLocked": false,
"loop": undefined,
"props": Object {}, "props": Object {},
"title": "",
}, },
Object { Object {
"children": Array [ "children": Array [
@ -130,7 +140,11 @@ Object {
Object { Object {
"componentName": "TextField", "componentName": "TextField",
"condition": true, "condition": true,
"conditionGroup": "",
"hidden": false,
"id": "node_k1ow3cbz", "id": "node_k1ow3cbz",
"isLocked": false,
"loop": undefined,
"props": Object { "props": Object {
"__category__": "form", "__category__": "form",
"__style__": Object {}, "__style__": Object {},
@ -200,11 +214,16 @@ Object {
"wrapperColOffset": 0, "wrapperColOffset": 0,
"wrapperColSpan": 0, "wrapperColSpan": 0,
}, },
"title": "",
}, },
Object { Object {
"componentName": "TextField", "componentName": "TextField",
"condition": true, "condition": true,
"conditionGroup": "",
"hidden": false,
"id": "node_k1ow3cc1", "id": "node_k1ow3cc1",
"isLocked": false,
"loop": undefined,
"props": Object { "props": Object {
"__category__": "form", "__category__": "form",
"__style__": Object {}, "__style__": Object {},
@ -270,11 +289,16 @@ Object {
"wrapperColOffset": 0, "wrapperColOffset": 0,
"wrapperColSpan": 0, "wrapperColSpan": 0,
}, },
"title": "",
}, },
Object { Object {
"componentName": "TextField", "componentName": "TextField",
"condition": true, "condition": true,
"conditionGroup": "",
"hidden": false,
"id": "node_k1ow3cc3", "id": "node_k1ow3cc3",
"isLocked": false,
"loop": undefined,
"props": Object { "props": Object {
"__category__": "form", "__category__": "form",
"__style__": Object {}, "__style__": Object {},
@ -340,23 +364,33 @@ Object {
"wrapperColOffset": 0, "wrapperColOffset": 0,
"wrapperColSpan": 0, "wrapperColSpan": 0,
}, },
"title": "",
}, },
], ],
"componentName": "Column", "componentName": "Column",
"condition": true, "condition": true,
"conditionGroup": "",
"hidden": false,
"id": "node_k1ow3cbx", "id": "node_k1ow3cbx",
"isLocked": false,
"loop": undefined,
"props": Object { "props": Object {
"__style__": Object {}, "__style__": Object {},
"colSpan": "", "colSpan": "",
"fieldId": "column_k1p1bnjm", "fieldId": "column_k1p1bnjm",
}, },
"title": "",
}, },
Object { Object {
"children": Array [ "children": Array [
Object { Object {
"componentName": "TextField", "componentName": "TextField",
"condition": true, "condition": true,
"conditionGroup": "",
"hidden": false,
"id": "node_k1ow3cc2", "id": "node_k1ow3cc2",
"isLocked": false,
"loop": undefined,
"props": Object { "props": Object {
"__category__": "form", "__category__": "form",
"__style__": Object {}, "__style__": Object {},
@ -422,11 +456,16 @@ Object {
"wrapperColOffset": 0, "wrapperColOffset": 0,
"wrapperColSpan": 0, "wrapperColSpan": 0,
}, },
"title": "",
}, },
Object { Object {
"componentName": "SelectField", "componentName": "SelectField",
"condition": true, "condition": true,
"conditionGroup": "",
"hidden": false,
"id": "node_k1ow3cc0", "id": "node_k1ow3cc0",
"isLocked": false,
"loop": undefined,
"props": Object { "props": Object {
"__category__": "form", "__category__": "form",
"__style__": Object {}, "__style__": Object {},
@ -512,21 +551,31 @@ Object {
"wrapperColOffset": 0, "wrapperColOffset": 0,
"wrapperColSpan": 0, "wrapperColSpan": 0,
}, },
"title": "",
}, },
], ],
"componentName": "Column", "componentName": "Column",
"condition": true, "condition": true,
"conditionGroup": "",
"hidden": false,
"id": "node_k1ow3cby", "id": "node_k1ow3cby",
"isLocked": false,
"loop": undefined,
"props": Object { "props": Object {
"__style__": Object {}, "__style__": Object {},
"colSpan": "", "colSpan": "",
"fieldId": "column_k1p1bnjn", "fieldId": "column_k1p1bnjn",
}, },
"title": "",
}, },
], ],
"componentName": "ColumnsLayout", "componentName": "ColumnsLayout",
"condition": true, "condition": true,
"conditionGroup": "",
"hidden": false,
"id": "node_k1ow3cbw", "id": "node_k1ow3cbw",
"isLocked": false,
"loop": undefined,
"props": Object { "props": Object {
"__style__": Object {}, "__style__": Object {},
"columnGap": "20", "columnGap": "20",
@ -534,17 +583,27 @@ Object {
"layout": "6:6", "layout": "6:6",
"rowGap": 0, "rowGap": 0,
}, },
"title": "",
}, },
], ],
"componentName": "CardContent", "componentName": "CardContent",
"condition": true, "condition": true,
"conditionGroup": "",
"hidden": false,
"id": "node_k1ow3cbk", "id": "node_k1ow3cbk",
"isLocked": false,
"loop": undefined,
"props": Object {}, "props": Object {},
"title": "",
}, },
], ],
"componentName": "Card", "componentName": "Card",
"condition": true, "condition": true,
"conditionGroup": "",
"hidden": false,
"id": "node_k1ow3cbj", "id": "node_k1ow3cbj",
"isLocked": false,
"loop": undefined,
"props": Object { "props": Object {
"__slot__extra": false, "__slot__extra": false,
"__slot__subTitle": false, "__slot__subTitle": false,
@ -576,6 +635,7 @@ Object {
"zh_CN": "基本信息", "zh_CN": "基本信息",
}, },
}, },
"title": "",
}, },
Object { Object {
"children": Array [ "children": Array [
@ -584,7 +644,11 @@ Object {
Object { Object {
"componentName": "TextField", "componentName": "TextField",
"condition": true, "condition": true,
"conditionGroup": "",
"hidden": false,
"id": "node_k1ow3cc4", "id": "node_k1ow3cc4",
"isLocked": false,
"loop": undefined,
"props": Object { "props": Object {
"__category__": "form", "__category__": "form",
"__style__": Object {}, "__style__": Object {},
@ -650,6 +714,7 @@ Object {
"wrapperColOffset": 0, "wrapperColOffset": 0,
"wrapperColSpan": 0, "wrapperColSpan": 0,
}, },
"title": "",
}, },
Object { Object {
"children": Array [ "children": Array [
@ -658,7 +723,11 @@ Object {
Object { Object {
"componentName": "TextField", "componentName": "TextField",
"condition": true, "condition": true,
"conditionGroup": "",
"hidden": false,
"id": "node_k1ow3cc8", "id": "node_k1ow3cc8",
"isLocked": false,
"loop": undefined,
"props": Object { "props": Object {
"__category__": "form", "__category__": "form",
"__style__": Object {}, "__style__": Object {},
@ -724,23 +793,33 @@ Object {
"wrapperColOffset": 0, "wrapperColOffset": 0,
"wrapperColSpan": 0, "wrapperColSpan": 0,
}, },
"title": "",
}, },
], ],
"componentName": "Column", "componentName": "Column",
"condition": true, "condition": true,
"conditionGroup": "",
"hidden": false,
"id": "node_k1ow3cc6", "id": "node_k1ow3cc6",
"isLocked": false,
"loop": undefined,
"props": Object { "props": Object {
"__style__": Object {}, "__style__": Object {},
"colSpan": "", "colSpan": "",
"fieldId": "column_k1p1bnjo", "fieldId": "column_k1p1bnjo",
}, },
"title": "",
}, },
Object { Object {
"children": Array [ "children": Array [
Object { Object {
"componentName": "TextField", "componentName": "TextField",
"condition": true, "condition": true,
"conditionGroup": "",
"hidden": false,
"id": "node_k1ow3cc9", "id": "node_k1ow3cc9",
"isLocked": false,
"loop": undefined,
"props": Object { "props": Object {
"__category__": "form", "__category__": "form",
"__style__": Object {}, "__style__": Object {},
@ -806,21 +885,31 @@ Object {
"wrapperColOffset": 0, "wrapperColOffset": 0,
"wrapperColSpan": 0, "wrapperColSpan": 0,
}, },
"title": "",
}, },
], ],
"componentName": "Column", "componentName": "Column",
"condition": true, "condition": true,
"conditionGroup": "",
"hidden": false,
"id": "node_k1ow3cc7", "id": "node_k1ow3cc7",
"isLocked": false,
"loop": undefined,
"props": Object { "props": Object {
"__style__": Object {}, "__style__": Object {},
"colSpan": "", "colSpan": "",
"fieldId": "column_k1p1bnjp", "fieldId": "column_k1p1bnjp",
}, },
"title": "",
}, },
], ],
"componentName": "ColumnsLayout", "componentName": "ColumnsLayout",
"condition": true, "condition": true,
"conditionGroup": "",
"hidden": false,
"id": "node_k1ow3cc5", "id": "node_k1ow3cc5",
"isLocked": false,
"loop": undefined,
"props": Object { "props": Object {
"__style__": Object {}, "__style__": Object {},
"columnGap": "20", "columnGap": "20",
@ -828,17 +917,27 @@ Object {
"layout": "6:6", "layout": "6:6",
"rowGap": 0, "rowGap": 0,
}, },
"title": "",
}, },
], ],
"componentName": "CardContent", "componentName": "CardContent",
"condition": true, "condition": true,
"conditionGroup": "",
"hidden": false,
"id": "node_k1ow3cbm", "id": "node_k1ow3cbm",
"isLocked": false,
"loop": undefined,
"props": Object {}, "props": Object {},
"title": "",
}, },
], ],
"componentName": "Card", "componentName": "Card",
"condition": true, "condition": true,
"conditionGroup": "",
"hidden": false,
"id": "node_k1ow3cbl", "id": "node_k1ow3cbl",
"isLocked": false,
"loop": undefined,
"props": Object { "props": Object {
"__slot__extra": false, "__slot__extra": false,
"__slot__subTitle": false, "__slot__subTitle": false,
@ -870,13 +969,18 @@ Object {
"zh_CN": "部门信息", "zh_CN": "部门信息",
}, },
}, },
"title": "",
}, },
Object { Object {
"children": Array [ "children": Array [
Object { Object {
"componentName": "Button", "componentName": "Button",
"condition": true, "condition": true,
"conditionGroup": "",
"hidden": false,
"id": "node_k1ow3cbn", "id": "node_k1ow3cbn",
"isLocked": false,
"loop": undefined,
"props": Object { "props": Object {
"__style__": ":root { "__style__": ":root {
margin-right: 16px; margin-right: 16px;
@ -912,11 +1016,16 @@ Object {
"triggerEventsWhenLoading": false, "triggerEventsWhenLoading": false,
"type": "primary", "type": "primary",
}, },
"title": "",
}, },
Object { Object {
"componentName": "Button", "componentName": "Button",
"condition": true, "condition": true,
"conditionGroup": "",
"hidden": false,
"id": "node_k1ow3cbp", "id": "node_k1ow3cbp",
"isLocked": false,
"loop": undefined,
"props": Object { "props": Object {
"__style__": ":root { "__style__": ":root {
width: 80px; width: 80px;
@ -945,11 +1054,16 @@ Object {
"triggerEventsWhenLoading": false, "triggerEventsWhenLoading": false,
"type": "normal", "type": "normal",
}, },
"title": "",
}, },
], ],
"componentName": "Div", "componentName": "Div",
"condition": true, "condition": true,
"conditionGroup": "",
"hidden": false,
"id": "node_k1ow3cbo", "id": "node_k1ow3cbo",
"isLocked": false,
"loop": undefined,
"props": Object { "props": Object {
"__style__": ":root { "__style__": ":root {
display: flex; display: flex;
@ -965,12 +1079,17 @@ Object {
"fieldId": "div_k1ow3h1o", "fieldId": "div_k1ow3h1o",
"useFieldIdAsDomId": false, "useFieldIdAsDomId": false,
}, },
"title": "",
}, },
], ],
"componentName": "Form", "componentName": "Form",
"condition": true, "condition": true,
"conditionGroup": "",
"extraPropA": "extraPropA", "extraPropA": "extraPropA",
"hidden": false,
"id": "form", "id": "form",
"isLocked": false,
"loop": undefined,
"props": Object { "props": Object {
"__style__": Object {}, "__style__": Object {},
"autoUnmount": true, "autoUnmount": true,
@ -992,26 +1111,38 @@ Object {
"size": "medium", "size": "medium",
"slotA": "", "slotA": "",
}, },
"title": "",
}, },
], ],
"componentName": "RootContent", "componentName": "RootContent",
"condition": true, "condition": true,
"conditionGroup": "",
"hidden": false,
"id": "node_k1ow3cbb", "id": "node_k1ow3cbb",
"isLocked": false,
"loop": undefined,
"props": Object { "props": Object {
"contentBgColor": "transparent", "contentBgColor": "transparent",
"contentMargin": "20", "contentMargin": "20",
"contentPadding": "0", "contentPadding": "0",
}, },
"title": "",
}, },
Object { Object {
"componentName": "RootFooter", "componentName": "RootFooter",
"condition": true, "condition": true,
"conditionGroup": "",
"hidden": false,
"id": "node_k1ow3cbc", "id": "node_k1ow3cbc",
"isLocked": false,
"loop": undefined,
"props": Object {}, "props": Object {},
"title": "",
}, },
], ],
"componentName": "Page", "componentName": "Page",
"condition": true, "condition": true,
"conditionGroup": "",
"css": "body{background-color:#f2f3f5}.card_kgaqfbm5 { "css": "body{background-color:#f2f3f5}.card_kgaqfbm5 {
margin-bottom: 12px; margin-bottom: 12px;
}.card_kgaqfbm6 { }.card_kgaqfbm6 {
@ -1042,7 +1173,9 @@ Object {
"online": Array [], "online": Array [],
"sync": true, "sync": true,
}, },
"hidden": false,
"id": "page", "id": "page",
"isLocked": false,
"lifeCycles": Object { "lifeCycles": Object {
"constructor": Object { "constructor": Object {
"compiled": "function constructor() { "compiled": "function constructor() {
@ -1070,6 +1203,7 @@ Object.keys(module.exports).forEach(function(item) {
"type": "js", "type": "js",
}, },
}, },
"loop": undefined,
"methods": Object { "methods": Object {
"__initMethods__": Object { "__initMethods__": Object {
"compiled": "function (exports, module) { /*set actions code here*/ }", "compiled": "function (exports, module) { /*set actions code here*/ }",

View File

@ -32,6 +32,12 @@ describe('document-model 测试', () => {
expect(doc.isBlank()).toBeFalsy(); expect(doc.isBlank()).toBeFalsy();
expect(doc.schema).toEqual({ expect(doc.schema).toEqual({
componentName: 'Page', componentName: 'Page',
condition: true,
conditionGroup: '',
hidden: false,
isLocked: false,
loop: undefined,
title: '',
id: 'root', id: 'root',
fileName: '', fileName: '',
props: {}, props: {},

View File

@ -249,7 +249,7 @@ describe('Node 方法测试', () => {
// getComponentName // getComponentName
btnParent.insertAfter({ getComponentName: () => 'Button' }, firstBtn); btnParent.insertAfter({ getComponentName: () => 'Button' }, firstBtn);
expect(btnParent.children.get(1)?.getProps().export().props).toBeUndefined(); expect(btnParent.children.get(1)?.getProps().export().props).toEqual({});
expect(mockFn).toHaveBeenCalledTimes(3); expect(mockFn).toHaveBeenCalledTimes(3);
}); });
}); });

View File

@ -71,14 +71,14 @@ const pages = Object.assign(project, {
componentsTree, componentsTree,
id: pages[0].id, id: pages[0].id,
config: project.config, config: project.config,
}, },
true, true,
); );
// FIXME: 根本原因是 PropStash 导致的在页面节点初始化结束后hideModalNodes 导致了第一次变化 // FIXME: 在页面节点初始化结束后,还有响应式变量变化导致了多次变化
// 这样可以避免页面加载之后就被标记为 isModified // 这样可以避免页面加载之后就被标记为 isModified
setTimeout(() => { setTimeout(() => {
project.currentDocument?.history.savePoint(); project.currentDocument?.history.savePoint();
}, 0); }, 1000);
}, },
addPage(data: OldPageData | RootSchema) { addPage(data: OldPageData | RootSchema) {
if (isPageDataV1(data)) { if (isPageDataV1(data)) {