Browse Source

Skip model resolver when possible

improve-loading-perfs
Artur Arseniev 4 weeks ago
parent
commit
a36dd20cd8
  1. 2
      packages/core/src/dom_components/model/Component.ts
  2. 3
      packages/core/src/dom_components/model/Components.ts
  3. 48
      packages/core/src/dom_components/model/ModelDataResolverWatchers.ts
  4. 4
      packages/core/src/dom_components/model/ModelResolverWatcher.ts
  5. 5
      packages/core/src/domain_abstract/model/StyleableModel.ts
  6. 9
      packages/core/src/undo_manager/index.ts
  7. 16
      packages/core/test/specs/undo_manager/index.ts

2
packages/core/src/dom_components/model/Component.ts

@ -2080,7 +2080,7 @@ export default class Component extends StyleableModel<ComponentProperties> {
const current = list[id];
if (!current) {
list[id] = model;
Component.setListId(list, id, model);
} else if (current !== model) {
const keepIdsCrossPages = model.em?.Components.config.keepAttributeIdsCrossPages;
const currentPage = current.page;

3
packages/core/src/dom_components/model/Components.ts

@ -405,7 +405,8 @@ Component> {
onAdd(model: Component, c?: any, opts: { temporary?: boolean } = {}) {
const { domc, em } = this;
const avoidInline = em.config.avoidInlineStyle;
domc && domc.Component.ensureInList(model);
const allById = domc?.allById();
allById?.[model.getId()] !== model && domc?.Component.ensureInList(model);
if (!avoidInline && em.config.forceClass && !opts.temporary) {
const style = model.getStyle();

48
packages/core/src/dom_components/model/ModelDataResolverWatchers.ts

@ -9,6 +9,7 @@ import { getSymbolsToUpdate, isSymbol } from './SymbolUtils';
import Component, { keySymbolOvrd } from './Component';
import { StyleableModelProperties } from '../../domain_abstract/model/StyleableModel';
import { isEmpty, isObject } from 'underscore';
import { isDataResolverProps } from '../../data_sources/utils';
export const updateFromWatcher = { fromDataSource: true, avoidStore: true };
export const keyDataValues = '__data_values';
@ -63,6 +64,25 @@ export class ModelDataResolverWatchers<T extends StyleableModelProperties> {
return evaluatedProps;
}
shouldResolveProps(props: ObjectAny) {
if (this.hasDataResolvers()) return true;
if (this.hasDataValues(props[keyDataValues])) return true;
if (this.hasResolverValue(props.attributes) || this.hasResolverValue(props.style)) return true;
const { excludedFromEvaluation } = this;
const propKeys = Object.keys(props);
for (let index = 0; index < propKeys.length; index++) {
const key = propKeys[index];
if (!excludedFromEvaluation.includes(key) && isDataResolverProps(props[key])) {
return true;
}
}
return false;
}
getProps(data: ObjectAny): ObjectAny {
const resolvedProps = this.getValueOrResolver('props', data);
const result = {
@ -137,6 +157,24 @@ export class ModelDataResolverWatchers<T extends StyleableModelProperties> {
return [this.propertyWatcher, this.styleWatcher, this.attributeWatcher];
}
private get excludedFromEvaluation() {
return ['components', 'dataResolver', 'status', 'state', 'open', keySymbolOvrd, keyDataValues];
}
private hasDataResolvers() {
return this.watchers.some((watcher) => watcher.hasDataResolvers());
}
private hasDataValues(dataValues: ObjectAny | undefined) {
return Object.values(dataValues || {}).some((value) => isObject(value) && !isEmpty(value));
}
private hasResolverValue(values: ObjectAny | string | undefined) {
if (!isObject(values)) return false;
return Object.values(values).some(isDataResolverProps);
}
private isComponent(model: any): model is Component {
return model instanceof Component;
}
@ -187,15 +225,7 @@ export class ModelDataResolverWatchers<T extends StyleableModelProperties> {
}
private filterProps(props: ObjectAny) {
const excludedFromEvaluation = [
'components',
'dataResolver',
'status',
'state',
'open',
keySymbolOvrd,
keyDataValues,
];
const { excludedFromEvaluation } = this;
const filteredProps = Object.fromEntries(
Object.entries(props).filter(([key]) => !excludedFromEvaluation.includes(key)),
);

4
packages/core/src/dom_components/model/ModelResolverWatcher.ts

@ -245,6 +245,10 @@ export class ModelResolverWatcher<T extends ObjectHash> {
return serializableValues;
}
hasDataResolvers() {
return Object.keys(this.resolverListeners).length > 0;
}
getValuesResolvingFromCollections() {
const keys = Object.keys(this.resolverListeners).filter((key: string) => {
return this.resolverListeners[key].resolver.resolvesFromCollection();

5
packages/core/src/domain_abstract/model/StyleableModel.ts

@ -98,7 +98,10 @@ export default class StyleableModel<T extends StyleableModelProperties = any> ex
}
this.dataResolverWatchers = this.dataResolverWatchers ?? options.dataResolverWatchers;
const evaluatedValues = this.dataResolverWatchers.addProps(attributes, options) as Partial<T>;
const shouldResolveProps = this.dataResolverWatchers.shouldResolveProps(attributes);
const evaluatedValues: Partial<T> = shouldResolveProps
? (this.dataResolverWatchers.addProps(attributes, options) as Partial<T>)
: (attributes as Partial<T>);
return super.set(evaluatedValues, options);
}

9
packages/core/src/undo_manager/index.ts

@ -148,9 +148,13 @@ export default class UndoManagerModule extends Module<UndoManagerConfig & { name
[EditorEvents.undo, EditorEvents.redo].forEach((ev) => this.um.on(ev, () => em.trigger(ev)));
}
get isDisabled() {
return !!this.config._disable;
}
postLoad() {
const { config, em } = this;
config.trackSelection && em && this.add(em.get('selected'));
config.trackSelection && !this.isDisabled && em && this.add(em.get('selected'));
}
/**
@ -169,6 +173,7 @@ export default class UndoManagerModule extends Module<UndoManagerConfig & { name
* um.add(someModelOrCollection);
*/
add(entity: any) {
if (this.isDisabled) return this;
this.um.register(entity);
return this;
}
@ -181,6 +186,7 @@ export default class UndoManagerModule extends Module<UndoManagerConfig & { name
* um.remove(someModelOrCollection);
*/
remove(entity: any) {
if (this.isDisabled) return this;
this.um.unregister(entity);
return this;
}
@ -192,6 +198,7 @@ export default class UndoManagerModule extends Module<UndoManagerConfig & { name
* um.removeAll();
*/
removeAll() {
if (this.isDisabled) return this;
this.um.unregisterAll();
return this;
}

16
packages/core/test/specs/undo_manager/index.ts

@ -25,6 +25,22 @@ describe('Undo Manager', () => {
expect(um.getStack()).toHaveLength(0);
});
test('Disabled undo manager does not track changes', () => {
const { editor, um } = setupTestEditor({
withCanvas: true,
config: { undoManager: false },
});
const wrapper = editor.getWrapper()!;
wrapper.append('<div></div>');
expect(um.isDisabled).toBe(true);
expect(um.hasUndo()).toBe(false);
expect(um.getStack()).toHaveLength(0);
editor.destroy();
});
describe('Component changes', () => {
test('Add component', () => {
expect(wrapper.components()).toHaveLength(0);

Loading…
Cancel
Save