-
Notifications
You must be signed in to change notification settings - Fork 61
Description
Description
When using SuperDoc with the collaboration module, the updateYdocDocxData() function broadcasts the entire DOCX document to all connected clients after every keystroke. This creates a significant performance bottleneck for real-time collaborative editing at scale.
Observed Behavior
Every keystroke triggers a large Y.Doc update with the full document:
[Y.Doc Update] {
origin: { event: 'docx-update', user: {...} },
updateSize: 23799 // ~23KB per keystroke!
}This happens in addition to the efficient Yjs CRDT delta sync (~200-300 bytes), effectively doubling the sync mechanism and negating the benefits of CRDT-based collaboration.
Impact at Scale
| Scenario | Bandwidth |
|---|---|
| 1 user typing 60 WPM (~5 chars/sec) | ~115KB/second broadcast |
| 10 concurrent editors | ~1.15MB/second |
| 100 concurrent editors | ~11.5MB/second |
This makes real-time collaboration impractical for documents with many concurrent users.
Root Cause Analysis
We traced this to the updateYdocDocxData() function which:
- Calls
editor.exportDocx({ getUpdatedDocs: true })- exports the entire document - Stores the result in the Y.Doc's
metamap as base64/XML - This triggers a sync to all connected clients
Code Locations (v1.8.x dist)
Main document listener (line ~14678) - Has 1-second debounce:
const initDocumentListener = ({ ydoc, editor }) => {
const debouncedUpdate = debounce((editor) => {
updateYdocDocxData(editor);
}, 1000); // 1 second debounce
ydoc.on("afterTransaction", (transaction) => {
if (!hasChangedDocx && transaction.changed?.size && local) {
debouncedUpdate(editor);
}
});
};Header/Footer update handler (line ~50727) - NO debounce:
const handleUpdate = async ({ transaction }) => {
// ...
await updateYdocDocxData(this.#editor, void 0); // Called on EVERY keystroke!
};
editor.on("update", handleUpdate);Expected Behavior
The full DOCX sync should:
- Be heavily debounced (e.g., 5-10 seconds, not 1 second)
- Be optional/disableable for collaboration-only mode where DOCX fidelity isn't needed in real-time
- Apply consistently - header/footer updates should also be debounced
- Only trigger on save/export rather than during active editing
Feature Request
Please consider adding configuration options:
const superdoc = new SuperDoc({
modules: {
collaboration: {
provider,
ydoc,
// New options:
syncDocxData: false, // Disable full DOCX sync entirely
docxSyncDebounce: 10000, // Or configure debounce interval (ms)
},
},
});Environment
- SuperDoc version: 1.8.3 (also tested on 1.7.0)
- Yjs version: 13.6.19
- @hocuspocus/provider: 2.15.3
- Browser: Chrome 131
- Use case: Legal document collaboration with potentially hundreds of concurrent users
Workaround Attempted
We attempted to find a configuration option to disable this behavior but found none in the public API. The debounce interval and sync behavior appear to be hardcoded.
Additional Context
This issue was discovered while debugging a separate cursor position bug (now resolved). The investigation revealed this performance concern which is critical for our production deployment.
SuperDoc version (if relevant)
1.7.0
Additional context
No response