Best practice to sync across tabs/ windows?

I’m working on a project, where multiple tabs / windows might be open and should stay in sync. y-indexeddb is used for local storage and it might be the case an online sync is not possible. So my first guess was, that y-indexeddb would look out for changes from other tabs and the update the doc. But this is not the case. I saw some broadcasting implementations in y-webrtc if I remember correctly.

However, my question is: what would be the best practice to implement multiple tab sync even if offline?

My idea was to use BroadcastChannel or a wrapper like https://discuss.yjs.dev/ and just fire a message, if an update is needed. What do you think? Thanks for your feedback.

I use both y-indexeddb and y-webrtc and syncing between tabs seems to work flawlessly without any modification and even when offline! I don’t know how but it just seems to work, its quite magical. Maybe it is because webrtc allows local peers to connect even when offline?

It seems to be done via BroadcastChannel in y-webrtc: y-webrtc/y-webrtc.js at master · yjs/y-webrtc · GitHub and lib0/broadcastchannel.js at main · dmonad/lib0 · GitHub

I guess it is up to the user, if he wants a different solution. I made something like this that worked for my case:

const client = uuid() // or String(Math.random())

let bc = new BroadcastChannel("yjs")

doc.on("update", (update: Uint8Array) => {
  bc.postMessage({ client, update })
})

bc.addEventListener("message", (msg) => {
  const { data } = msg
  if (data.client !== client) {
    Y.applyUpdate(doc, data.update)
  }
})
2 Likes

Right, broadcastchannel is what y-websocket and y-webrtc use to share content between windows. Note that we don’t create a webrtc connection if there is a broadcastchannel connection.

Thanks for the example @holtwick! The example is close to complete: you also need to share the initial state of the document whenever a new client joins. This is why we broadcast a “sync step 1” over the broadcastchannel whenever a new provider is created. All clients connected to the same room will reply with the initial content (which is just a small overhead because of the efficiency of Broadcastchannel).

Another thing that you need to solve is to share the awareness information.

I think the easiest solution to share content over broadcastchannel (even if you implemented your own provider) is to use the y-websocket provider and disable the network connection. Simply call disconnectWs() after you instanciate the provider. The broadcastchannel will still work.

1 Like

hi! disconnectWs is not there anymore, how can I stop websocket connection and keep the broadcast working? TIA!

1 Like

@dmonad also running up against this (opening in a document in a second tab results in the document in the new tab to be blank with an error). I see that bcconnected is connected. You mention using disconnectWs() but I’m not seeing that available anywhere. Any help would be appreciated!

I guess I never actually implemented that… Would be open to a PR to y-websocket

I’m implementing y-tabssync, you could merge in the same repo if you want. now for testing I’m having a general problem, is that there is no YjsSuspense which means I can’t know when the sync happened to show content / there are two issues I don’t have synced true anymore, it was part of websockets / and second, how do I know it synced if it is the only tab opened?