I have a plugin that gets all the users who have written in a line and draws a circle with their initials beside the line.
This was working fine but the problem is that it gets slow for big documents. The main problem is that for every keystroke it builds again the DOM for the decorations widgets.
private getDecorationWidgets(lines: Line[]){
return lines.map(line => Decoration.widget(line.firstCharProseMirrorPosition, line.lineAuthorsDOM, {side: -1}) );
}
so I tried to optimize it by saving the lines with the authors DOM in the plugin state and at every key stroke I only build the DOM for the new lines, reusing the DOM created for the old ones.
if(oldPluginState.decorations === DecorationSet.empty || tr.docChanged){
const lines = this.getAllCanvasLines(authorTracking, newEditorState.doc);
const linesWithDOM = this.getLinesWithDOM(lines, oldPluginState.lines);
const decorations = this.getDecorationWidgets(linesWithDOM);
newPluginState = {
decorations: DecorationSet.create(newEditorState.doc, decorations),
lines: linesWithDOM
};
}
.....
private getLinesWithDOM(lines: Line[], oldLinesWithDOM: Line[]){
return lines.map(currentLine => {
const oldLine = oldLinesWithDOM.find(line => this.equals(currentLine, line));
if(oldLine){
currentLine.lineAuthorsDOM = oldLine.lineAuthorsDOM;
}else{
currentLine.lineAuthorsDOM = this.buildComponent(currentLine.userIds);
}
return currentLine;
});
}
This also was working fine but now for some documents I get this error:
TypeError: Cannot read property ‘nextSibling’ of null at rm (http://localhost:8080/vendor.bundle.js:59944:17) at renderDescs (http://localhost:8080/vendor.bundle.js:59839:39) at NodeViewDesc.renderChildren (http://localhost:8080/vendor.bundle.js:59650:5) at NodeViewDesc.updateChildren (http://localhost:8080/vendor.bundle.js:59646:64) at NodeViewDesc.updateInner (http://localhost:8080/vendor.bundle.js:59668:33) at NodeViewDesc.update (http://localhost:8080/vendor.bundle.js:59660:10) at ViewTreeUpdater.updateNextNode (http://localhost:8080/vendor.bundle.js:60042:14) at http://localhost:8080/vendor.bundle.js:59636:17 at iterDeco (http://localhost:8080/vendor.bundle.js:60098:7) at NodeViewDesc.updateChildren (http://localhost:8080/vendor.bundle.js:59623:5) at NodeViewDesc.updateInner (http://localhost:8080/vendor.bundle.js:59668:33) at NodeViewDesc.update (http://localhost:8080/vendor.bundle.js:59660:10) at ViewTreeUpdater.updateNextNode (http://localhost:8080/vendor.bundle.js:60042:14) at http://localhost:8080/vendor.bundle.js:59636:17 at iterDeco (http://localhost:8080/vendor.bundle.js:60098:7) at NodeViewDesc.updateChildren (http://localhost:8080/vendor.bundle.js:59623:5) at NodeViewDesc.updateInner (http://localhost:8080/vendor.bundle.js:59668:33) at NodeViewDesc.update (http://localhost:8080/vendor.bundle.js:59660:10) at ViewTreeUpdater.updateNextNode (http://localhost:8080/vendor.bundle.js:60042:14) at http://localhost:8080/vendor.bundle.js:59636:17 at iterDeco (http://localhost:8080/vendor.bundle.js:60098:7) at NodeViewDesc.updateChildren (http://localhost:8080/vendor.bundle.js:59623:5) at NodeViewDesc.updateInner (http://localhost:8080/vendor.bundle.js:59668:33) at NodeViewDesc.update (http://localhost:8080/vendor.bundle.js:59660:10) at EditorView.updateState (http://localhost:8080/vendor.bundle.js:5083:25) at CanvasComponent.handleCanvasStateChange
I assume that because I am reusing the DOM somehow ProseMirror tries to delete it more than once, it makes sense but it is funny that most part of the times it doesn’t happen.
How can I make my plugin fast without running into this problem ?