yjs / yjs-demos

A collection of demos for Yjs
https://demos.yjs.dev
The Unlicense
729 stars 120 forks source link

Tip Tap with initial content duplicated #16

Closed arnold-graf closed 4 years ago

arnold-graf commented 4 years ago

Hi!

I’ve been trying to integrate the TipTap-Yjs example into a Vue project. I set the initial content of the editor using the content prop (i.e.: new Editor({ extensions: […], content: 'some html' })), and everything works smoothly. However, as soon as a second client connects to the YDoc via WebRTC, the content duplicates, and i get some html some html as the content of the editor on both clients.

I figure this must be a common mistake, but I couldn’t find anything about duplicated content on any Issue Boards.

Any help is much appreciated and thank you so much for your work!

dmonad commented 4 years ago

Hey @arnold-graf ,

yeah, this is a common mistake. We discussed this several times in the chat, but not yet in the forum or the GitHub issues.

As soon as you bind Yjs to an editor, it will overwrite the editor content with the value in the Yjs type. In TipTap the initial value is apparently written after the y-prosemirror initialization step, so the content is written in the empty Yjs document. So your "initial" TipTap content is again synced to the other peers.

My recommendation is to store and retrieve the Yjs document on your servers, instead of the TipTap data model. Of course, you can also store the TipTap data format alongside the Yjs document. But if you use the Yjs document to restore the document state, you won't have any sync conflicts / duplicated content with other peers.

This section explains how you get and restore document updates in Yjs https://github.com/yjs/yjs#Document-Updates

// encode the Yjs document to a Uint8Array:
const savedDoc = Y.encodeStateAsUpdate(ydoc1)
// send savedDoc to your server

// in order to populate the initial Yjs document, retrieve doc from the server and apply it to a Yjs document:
const doc = new Y.Doc()
Y.applyUpdate(doc, savedDoc)

Note: If possible, send the binary data directly to your server. If you must send it as a JSON object, you can use Base64 encoding to transform savedDoc to a string (you'll find many Base64 encoder/decoder on the internet). Do not send it as an array of integers to the server, that would be horribly inefficient ;)

Hope this helps.