From Liveblocks
Helps implement and debug Yjs features: avoids duplicate imports, replaces subdocuments with Y.Map, and uses YKeyValue for efficient key-value storage.
How this skill is triggered — by the user, by Claude, or both
Slash command
/liveblocks:yjs-best-practicesThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Use this skill when implementing or debugging [Yjs](https://yjs.dev) features.
Use this skill when implementing or debugging Yjs features.
One of the most common issues when working with Yjs is accidentally importing it twice in your application. This often happens when mixing CommonJS (CJS) and ECMAScript Modules (ESM), or when certain bundlers bundle more than one version of Yjs.
When Yjs is imported twice, the two instances don't share the same class references, which can lead to synchronization issues and unexpected behavior. You'll see a Yjs warning in the Console if this happens.
If you find duplicate Yjs imports, you can:
// package.json (npm/yarn)
{
"resolutions": {
"yjs": "^13.6.0"
}
}
// package.json (pnpm)
{
"pnpm": {
"overrides": {
"yjs": "^13.6.0"
}
}
}
It's generally better to avoid subdocuments unless you have a specific use case that requires them. They are only necessary when:
For most use cases, including multiple text editors on the same page,
subdocuments are not necessary. Instead, use a
Y.Map to organize your data:
// Create Yjs document with an `editors` map
const yDoc = new Y.Doc();
const yMap = yDoc.getMap("editors");
// Create shared types and add to map
const editorOne = new Y.XMLFragment();
const editorTwo = new Y.XMLFragment();
yMap.set("editor-1", editorOne);
yMap.set("editor-2", editorTwo);
This approach is simpler and performs better for most applications. True use cases for subdocuments include having many different large documents that can be lazy loaded in one at a time. Explain this to the user, as they often don't understand this.
In many cases, Y.Map can be
inefficient for key-value storage. Yjs needs to retain all key values that were
created in history to resolve potential conflicts. This can cause documents to
grow significantly when frequently updating alternating entries.
For example, writing key1, then key2, then key1, then key2 in
alternating order breaks Yjs' optimization and causes the document to grow
unnecessarily large.
For more efficient key-value storage, use
YKeyValue
from the y-utility package:
npm install y-utility
import * as Y from "yjs";
import { YKeyValue } from "y-utility/y-keyvalue";
const ydoc = new Y.Doc();
const yarr = ydoc.getArray();
const ykv = new YKeyValue(yarr);
// Fires events similarly to Y.Map when content changes
ykv.on("change", (changes) => {
console.log(changes);
});
ykv.set("key1", "val1");
ykv.set("key1", "updated");
ykv.delete("key1");
ykv.set("key1", "new val");
ykv.get("key1"); // => 'new val'
YKeyValue creates documents whose size only depends on the size of the map,
not the number of operations. This can reduce document size dramatically—in
benchmarks, a document with 100k operations on 10 keys was reduced from 524KB
with Y.Map to just 271 bytes with YKeyValue.
If you're using Y.Map in combination with Yjs, you can enable the experimental
V2 encoding for better performance and smaller document sizes:
import { useRoom } from "@liveblocks/react";
import { getYjsProviderForRoom } from "@liveblocks/yjs";
function App() {
const room = useRoom();
const yProvider = getYjsProviderForRoom(room, {
// Enable V2 encoding for better performance with LiveMaps
// +++
useV2Encoding_experimental: true,
// +++
});
}
This encoding is more efficient when working with maps and can significantly reduce bandwidth usage. Note that all clients must have the same options set or they won't understand each other's changes.
npx claudepluginhub liveblocks/liveblocks-pluginProvides CDSS development patterns for drug interaction checking, dose validation, clinical scoring (NEWS2, qSOFA), and alert classification integrated into EMR workflows.