Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
yjs-vue3-experiment.vue
<template>
<div class="test-sfu">
<div class="prose">
<h1>
<router-link to="/test">Test Vue3 + Yjs</router-link>
</h1>
<p>Experiment to combine Vue3 reactivity and Yjs realtime sync.</p>
<p>
Play around on the console by changing values of
<code>window.realtime</code>
object, like <code>window.realtime.left.test = 123</code>.
</p>
</div>
<div class="test-sfu-videos">
<div>
Left
<tw-debug :data="realtime.left" />
</div>
<div>
Right
<tw-debug :data="realtime.right" />
</div>
</div>
<tw-debug :data="realtime" level="3" />
</div>
</template>
<style lang="stylus">
@require "../twindy/index.styl"
.test-sfu
margin 24
.test-sfu-videos
display grid
grid-template-columns: repeat(2, minmax(50%, 400px))
gap 24px
margin-y 24
</style>
<script lang="ts">
import { Logger } from "@/lib/log"
import { state } from "@/state"
import { cloneObject, deepEqual } from "lib"
import { twDebug } from "twindy-headless"
import { defineComponent, reactive, watch } from "vue"
import * as Y from "yjs"
const log = Logger("test-realtime")
const doc1 = new Y.Doc()
const doc2 = new Y.Doc()
doc1.on("update", (update: Uint8Array) => {
log("doc left to right apply", update.length)
Y.applyUpdate(doc2, update)
})
doc2.on("update", (update: Uint8Array) => {
log("doc right to left apply", update.length)
Y.applyUpdate(doc1, update)
})
const realtime = reactive({
left: {
left: "left",
},
right: {
right: "right",
},
})
let left = doc1.getMap("demo")
left.observe(() => {
let value = cloneObject(left.toJSON())
log("left observed change", value)
Object.assign(realtime.left, value) // in place
})
let right = doc2.getMap("demo")
right.observe(() => {
let value = cloneObject(right.toJSON())
log("right observed change", value)
Object.assign(realtime.right, value) // in place
})
function sync(reactiveObj, realtimeObj) {
let obj = cloneObject(reactiveObj)
let yobj = realtimeObj.toJSON()
Object.entries(obj).forEach(([key, value]) => {
const eq = deepEqual(value, yobj[key])
log("sync", eq, key, value, yobj[key])
if (!eq) {
realtimeObj.set(key, value as any)
}
})
}
watch(realtime.left, (obj) => {
log("watched realtime.left", obj)
sync(realtime.left, left)
})
watch(realtime.right, (obj) => {
log("watched realtime.right", obj)
sync(realtime.right, right)
})
// @ts-ignore
window.realtime = realtime
export default defineComponent({
components: {
twDebug,
},
setup() {
return {
state,
realtime,
}
},
})
</script>
@holtwick
Copy link
Author

holtwick commented May 4, 2021

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment