Summary
On a large document (~132 KB / ~14k lines), clicking Reply on a comment freezes the tab (Chrome "Page Unresponsive"). Loading and reading the same document are fine, and the identical reply flow on a small document is instant. The cause appears to be a full-document decoration rebuild triggered on comment-state changes.
Environment
- Self-hosted, editor loaded from
/d/<slug>
- Document: single doc, ~132 KB markdown, ~14k lines
- Version:
fb25787
Symptom
- Open a large doc, scroll to a paragraph with a comment.
- Click Reply (or start typing a reply).
- Tab main thread blocks → "Page Unresponsive". Small docs: no freeze.
Suspected cause
src/editor/plugins/comments.ts rebuilds decorations across the entire document on comment changes:
comments.ts:123 — doc.descendants((node, pos) => { … }) walks every node.
comments.ts:369 — return DecorationSet.create(state.doc, decorations); rebuilds the full set.
On a ~14k-node document this O(nodes) rebuild runs synchronously in the comment/reply path and blocks the main thread. Reply and resolve don't change comment anchors, so a full anchor rescan shouldn't be needed for them.
Suggested fix
- Map the existing
DecorationSet through the transaction (decorationSet.map(tr.mapping, tr.doc)) and only recompute ranges affected by anchor changes, instead of rebuilding from scratch on every comment-state change.
- For reply/resolve (no anchor change), skip decoration recomputation entirely.
Found while debugging a self-hosted instance with Claude Code. Happy to test a patch against the large doc that reproduces it.
Summary
On a large document (~132 KB / ~14k lines), clicking Reply on a comment freezes the tab (Chrome "Page Unresponsive"). Loading and reading the same document are fine, and the identical reply flow on a small document is instant. The cause appears to be a full-document decoration rebuild triggered on comment-state changes.
Environment
/d/<slug>fb25787Symptom
Suspected cause
src/editor/plugins/comments.tsrebuilds decorations across the entire document on comment changes:comments.ts:123—doc.descendants((node, pos) => { … })walks every node.comments.ts:369—return DecorationSet.create(state.doc, decorations);rebuilds the full set.On a ~14k-node document this O(nodes) rebuild runs synchronously in the comment/reply path and blocks the main thread. Reply and resolve don't change comment anchors, so a full anchor rescan shouldn't be needed for them.
Suggested fix
DecorationSetthrough the transaction (decorationSet.map(tr.mapping, tr.doc)) and only recompute ranges affected by anchor changes, instead of rebuilding from scratch on every comment-state change.Found while debugging a self-hosted instance with Claude Code. Happy to test a patch against the large doc that reproduces it.