We’ve all been there. You’ve just gotten comfortable on your flight, confident that the in-flight Wi-Fi will perform admirably, only to discover that there will be no internet available on today’s flight. What do you do when you have a mission-critical document that you have to deliver by the time the wheels touch the asphalt at your destination? For many developers, the concept of offline-enabled applications leads to anxiety and panic. But the pain is over thanks to the multiplicity of benefits provided by the pairing of emerging web technologies like the open-source real-time collaboration framework known as Yjs and the local database technology ideal for offline solutions known as IndexedDB. When coupled with Service Workers, even more exciting potential is unlocked.
Recently, your correspondent (Preston So, Editor in Chief at Tag1 and author of Decoupled Drupal in Practice) had a wonderful time hosting a _Tag1 Team Talks _episode concerning the ways in which Yjs empowers and enriches offline-first applications, thanks to my fellow colleagues Kevin Jahns (creator of Yjs and Real-Time Collaboration Systems Lead at Tag1), Fabian Franz (Senior Technical Architect and Performance Lead at Tag1), and Michael Meyers (Managing Director at Tag1). In this multi-part blog series about Yjs offline editing, we cover everything from high-level use cases to the nitty-gritty of how Yjs enables offline applications. In this fourth installment of the series, we cover conflict resolution.
How Yjs enables conflict resolution
Just before we start delving into the ideas in question, I highly recommend that you consult the first, second, and third installments of this blog series in order to grasp as completely as possible the origins of offline capabilities thanks to Yjs, IndexedDB, and Service Workers, as well as the ways in which Web Workers can enhance your experience. I also invite you to return to the previous installments in this blog post for some intriguing discussion about how Drupal can enable offline editing and whether Yjs-driven approaches to offline-enabled applications also support security requirements such as end-to-end encryption.
During our recent conversation, Fabian vividly illustrated a scenario that is relevant to everyone who requires offline editing use cases. Consider the following situation: You have many changes on your local machine that need to be synchronized upstream without any conflicts. Fortunately, Yjs can resolve all of these conflicts, but less fortunately, such operations involving conflict resolution inevitably create some latency in the process.
Nonetheless, as a user, particularly nowadays, latency is anathema to a successful end user experience. As a user, we seldom are content with a spinning circle indicating that our content is still loading while data is being synchronized. If all of this work is instead placed into a Web Worker, you can already begin working in your document and visualize live changes that have been synchronized. This is because Web Worker operations all occur in the background, and a Web Worker offers you a medium through which these interactions will happen without blocking other user interactions in the process, a crucial ask for any content collaborator.
The importance of user feedback
After all, one of the value propositions provided by Yjs is the notion of real-time editing. But one of the most important considerations when it comes to real-time editing is the responsiveness illustrated by the user receiving some sort of feedback as soon as every keystroke lands. If I tap a key in an autosave environment and there is no local functionality available to capture this event, the fact that I pressed a key needs to travel all the way back to the server and return as a response to me through a round trip, a particularly inefficient procedure.
Consider, for example, the case of Google Docs. Even if you make use of Google Docs on a low-latency connection, a slow Google Docs document will nevertheless require an eternity to register keystrokes. This is one of the contexts in which Web Workers and IndexedDB can significantly and noticeably accelerate progress, and Service Workers likewise play an important role in what Fabian calls the “perfect triangle of elements” to enable offline editing.
Content synchronization as an expected step
Michael commented during our recent Tag1 Team Talks episode about implementing offline collaborative editing with Yjs that our discussion above gave him traumatic flashbacks to writing e-mail in environments with limited connectivity. Trying to send an e-mail while offline through Gmail was always a nightmare, with a perpetual countdown that sometimes seemed unending. His question during our show was: Could Yjs potentially enable e-mail services like Gmail to function offline so that e-mails written offline could be submitted back to the server later?
Kevin responded by saying that although such an approach is feasible without the requirement of Yjs as a dependency, any collaborative environment involving multiple authors requires the use of Yjs due to the fact that other clients need to be able to modify the document in question. In the process, Kevin goes on to state that a very involved synchronization framework is necessary to make this vision possible. After all, in the case of a typical Google Docs document, we can easily understand when server sync fails thanks to the errors thrown by a failed POST request. With Service Workers, you can ensure that Service Workers store the request offline and issue it later once internet access is regained.
Kevin takes pains to state that this is the same scenario in Yjs. If you are building a React application, you can actually leverage Yjs to share state across both frameworks by storing it to IndexedDB. Then, all you need to do is to determine with the support of Yjs when it is most appropriate to synchronize the content to the server.
From a server–client model to a synchronization model
At this point in our Tag1 Team Talks episode, Fabian makes a key argument that sums up many of the thoughts that we had over the course of our discussion. Fabian argues convincingly that we are up against a transition from the traditional server–client model to one involving synchronization. According to Fabian, this is a key notion because, as Kevin mentioned earlier, a traditional React application involving many state changes requires that those state changes eventually end up stored in some server through POST requests.
Admittedly, if such operations fail, the application on the front end can always attempt once more, but Fabian encourages us to imagine that this is no longer necessary; we can leverage a Y array and use Yjs primitives to store said data to the server eventually when the server is finally available once more. This represents a wholly different approach to thinking about applications and how data enters and exits those applications.
The above scenario illustrates effectively why offline-first functionality is so easy to enable with the help of Yjs. Yjs can not only act as a collaboration tool for text but also other types of data, as we discussed in other _Tag1 Team Talks _episodes, and because Yjs is built fundamentally on data types, you can, for instance, construct a collaborative to-do list simply by creating a data structure that is collaborative.
As soon as you have a content item in the mix in Yjs, this data entity gets synchronized with the server and other clients automatically, thanks to peer-to-peer functionality covered in another previous Tag1 Team Talks episode. This approach, and this set of features, is, in Fabian’s opinion, in its own way a sort of revolution that enables an exciting future for collaborative editing even when offline. And with the sum of all of these approaches together, we can implement rich collaborative applications that function efficiently and effectively irrespective of your connectivity at the time.
These days, it seems that there is no shortage of new approaches for web applications. Nonetheless, over the last several years, one requirement often expressed by enterprise organizations remains constant; the need for offline-enabled functionality regardless of whether the user is connected or not. Fortunately, with the help of Yjs, an open-source real-time collaboration framework, and IndexedDB, an emerging standard now available in all browsers as a local database, developers find it easier than ever to work with offline applications for a variety of use cases, all with the support of Yjs, y-indexeddb, Service Workers, and Web Workers.
In this fourth installment of this blog series about offline editing with Yjs, we covered conflict resolution and some of the unique value propositions represented by Yjs when it comes to offline editing in conjunction with IndexedDB. We also delved into some of the ways in which a new revolution is occurring in content architectures, one in which the traditional client–server is rapidly being replaced in many cases by a model centered around content synchronization and conflict resolution. In the next installment of this blog series, we cover how Yjs’ offline editing capabilities can encompass peer-to-peer collaboration and performant garbage collection as well.
For more Yjs content, see Yjs - Add real-time collaboration to any application.