Mutan j/mutan yjs: perpustakaan untuk membangun aplikasi web kolaboratif yjs – Beragampengetahuan
Perpustakaan untuk Membangun Aplikasi Web Kolaboratif YJS Menggunakan Mutasi.
Mutasi adalah basis data yang berkinerja tinggi dan tidak dapat diubah dari struktur data untuk JavaScript. Y.JS adalah perpustakaan CRDT dengan API berbasis mutasi. mutative-yjs Memungkinkan manipulasi tipe data Y.JS menggunakan API yang disediakan mutasi.
- 🔄 Sinkronisasi dua arah: Sinkronisasi mulus antara jenis YJS CRDT dan objek JavaScript biasa
- 🎯 Pembaruan yang tidak berubah: Gunakan draft API intuitif mutasi untuk pembaruan status
- 📦 Ketik aman: Dukungan penandaan yang komprehensif dengan penalaran jenis
- 🚀 Pertunjukan: Pembaruan berbasis tambalan yang efektif melalui berbagi struktur
- 🔌 Fleksibel: Aplikasi tambalan yang dapat disesuaikan untuk kasus penggunaan lanjutan
- 📡 Responsif: Sistem langganan bawaan untuk perubahan status
- ⚡ Transaksi eksplisit: Pembaruan Y.JS batch dalam transaksi, Anda dapat mengontrol batasan
- 🪶 Lampu: Sederhana, basis kode kecil tanpa sihir atau kunci vendor
- 🎨 Non-invasif: Selalu pilih alami (snapshot hanyalah objek biasa)
Melakukan:
// any operation supported by mutative
binder.update((state) =>
state.nested[0].key =
id: 123,
p1: 'a',
p2: ['a', 'b', 'c'],
;
);
Alih-alih:
Y.transact(state.doc, () =>
const val = new Y.Map();
val.set('id', 123);
val.set('p1', 'a');
const arr = new Y.Array();
arr.push(['a', 'b', 'c']);
val.set('p2', arr);
state.get('nested').get(0).set('key', val);
);
npm install mutative-yjs mutative yjs
# or
yarn add mutative-yjs mutative yjs
# or
pnpm add mutative-yjs mutative yjs
import * as Y from 'yjs';
import bind from 'mutative-yjs';
// Create a Yjs document
const doc = new Y.Doc();
const yMap = doc.getMap('data');
// Bind the Yjs data structure
const binder = bind< count: number; items: string[] >(yMap);
// Initialize with data
binder.update((state) =>
state.count = 0;
state.items = ['apple', 'banana'];
);
// Update state using Mutative's draft API
binder.update((state) =>
state.count++;
state.items.push('orange');
);
// Get current snapshot
console.log(binder.get()); // count: 1, items: ['apple', 'banana', 'orange']
// Subscribe to changes
const unsubscribe = binder.subscribe((snapshot) =>
console.log('State updated:', snapshot);
);
// Changes from Yjs are automatically reflected
yMap.set('count', 5);
console.log(binder.get().count); // 5
// Clean up
unsubscribe();
binder.unbind();
import bind from 'mutative-yjs'.- Buat perekat:
const binder = bind(doc.getMap("state")). - Tambahkan langganan ke snapshot:
binder.subscribe(listener).- Mutasi dalam tipe data Y.JS akan memicu langganan snapshot.
- Menelepon
update(...)(Mirip dengancreate(...)Dalam mutasi) akan memperbarui jenis Y.JS yang sesuai dan memicu langganan snapshot.
- panggilan
binder.get()Untuk mendapatkan snapshot terbaru. - (Opsional) Panggilan
binder.unbind()Lepaskan pengamat.
Y.Map Menggabungkan benda biasa ,,,,, Y.Array Dikombinasikan dengan array biasa []dan level bersarang apa pun Y.Map/Y.Array Dikombinasikan dengan objek/array JSON normal bersarang.
Y.XmlElement Dan Y.Text Tidak ada yang setara dengan tipe data JSON, sehingga tidak didukung secara default. Jika Anda ingin menggunakannya, gunakan tipe tingkat atas Y.JS (mis. doc.getText("xxx")) Lihat secara langsung atau lihat Binding dan pola khusus Bagian di bawah ini.
Taman bermain demonstrasi
Ikat tipe data YJS untuk membuat instance binder.
parameter:
source:Y.Map<any> | Y.Array<any>– Ikatan tipe data YJSoptions?:Options<S>– Konfigurasi opsional
kembali: Binder<S> – Contoh perekat, metode berinteraksi dengan batasan
contoh:
const doc = new Y.Doc();
const yMap = doc.getMap('myData');
const binder = bind<MyDataType>(yMap);
Contents
createBinder(source, initialState, options?)
Buat perekat dengan keadaan awal dalam satu panggilan. Ini adalah fitur kenyamanan gabungan bind() dan inisialisasi.
parameter:
source:Y.Map<any> | Y.Array<any>– Ikatan tipe data YJSinitialState:S– Keadaan awal yang akan ditetapkanoptions?:Options<S>– Konfigurasi opsional
kembali: Binder<S> – Contoh perekat dengan keadaan awal
contoh:
const doc = new Y.Doc();
const yMap = doc.getMap('myData');
const binder = createBinder(yMap, count: 0, items: [] );
Mengembalikan snapshot dari data saat ini.
const snapshot = binder.get();
Perbarui status menggunakan fitur draft mutasi. Perubahan berlaku untuk snapshot dan struktur data YJS yang mendasari.
parameter:
fn:(draft: S) => void– Fungsi untuk menerima status draft dengan mutasi
binder.update((state) =>
state.user.name = 'John';
state.items.push( id: 1, title: 'New Item' );
);
binder.subscribe(fn, options?)
Perubahan Status Berlangganan. Ketika panggilan balik dipanggil dengan cara berikut:
update()Ditelepon- Data YJS dasar telah dimodifikasi
parameter:
fn:(snapshot: S) => void– Fungsi panggilan balik untuk menerima snapshot baruoptions?:SubscribeOptions– Konfigurasi Langganan Opsionalimmediate?: boolean– Jika benar, silakan gunakan snapshot saat ini untuk segera menghubungi Invoker
kembali: UnsubscribeFn – Fungsi berhenti berlangganan
// Basic subscription
const unsubscribe = binder.subscribe((snapshot) =>
console.log('State changed:', snapshot);
);
// Subscribe with immediate execution
binder.subscribe((snapshot) =>
console.log('Current state:', snapshot);
, immediate: true );
// Later...
unsubscribe();
Lepaskan perekat dan lepaskan pengamat YJS. Setelah Anda menyelesaikan binder, hubungi.
Seperti mutasi, mutative-yjs Memberikan berbagi struktur yang efektif. Bagian negara yang tidak berubah menyimpan referensi yang sama, yang sangat bermanfaat untuk reaksi ulang:
const snapshot1 = binder.get();
binder.update((state) =>
state.todos[0].done = true;
);
const snapshot2 = binder.get();
// changed properties have new references
snapshot1.todos !== snapshot2.todos;
snapshot1.todos[0] !== snapshot2.todos[0];
// unchanged properties keep the same reference
snapshot1.todos[1] === snapshot2.todos[1];
snapshot1.todos[2] === snapshot2.todos[2];
Anda dapat menyesuaikan cara menerapkan tambalan mutasi ke struktur data YJS:
const binder = bind<MyDataType>(yMap,
applyPatch: (target, patch, defaultApplyPatch) =>
// Inspect or modify the patch before applying
console.log('Applying patch:', patch);
// You can conditionally apply patches based on the path
if (patch.path[0] === 'protected')
// Skip protected fields
return;
// Delegate to default behavior
defaultApplyPatch(target, patch);
// Or implement custom logic
// ...
,
);
Cara menghasilkan tambalan untuk mutasi konfigurasi:
const binder = bind<MyDataType>(yMap,
patchesOptions:
pathAsArray: true,
arrayLengthAssignment: true,
,
);
Untuk detail lebih lanjut tentang opsi tambalan, lihat dokumentasi patch mutasi.
Semua perpustakaan dapat digunakan Y.Map Dan Y.Array:
const doc = new Y.Doc();
const yArray = doc.getArray('items');
type Item = id: string; name: string ;
const binder = bind<Item[]>(yArray);
binder.update((items) =>
items.push( id: '1', name: 'First Item' );
items.push( id: '2', name: 'Second Item' );
);
// Array operations work as expected
binder.update((items) =>
items[0].name = 'Updated Name';
items.splice(1, 1); // Remove second item
);
Contoh pengeditan kolaboratif
import * as Y from 'yjs';
import WebsocketProvider from 'y-websocket';
import bind from 'mutative-yjs';
// Create document and connect to server
const doc = new Y.Doc();
const provider = new WebsocketProvider('ws://localhost:1234', 'room-name', doc);
const yMap = doc.getMap('shared-data');
const binder = bind<AppState>(yMap);
// Subscribe to remote changes
binder.subscribe((snapshot) =>
// Update UI with new state
renderApp(snapshot);
);
// Make local changes
function handleUserAction()
binder.update((state) =>
state.todos.push(
id: generateId(),
text: 'New todo',
completed: false,
);
);
menggunakan useSyncExternalStoreWithSelector Untuk integrasi reaksi yang optimal, dengan berlangganan selektif:
import * as Y from ‘yjs’;
// define state shape
interface State
todos: Array< id: string; text: string; done: boolean >;
user: name: string; email: string ;
const doc = new Y.Doc();
// define store
const binder = bind<State>(doc.getMap(‘data’));
// define a helper hook
function useMutativeYjs<Selection>(selector: (state: State) => Selection)
const selection = useSyncExternalStoreWithSelector(
binder.subscribe,
binder.get,
binder.get,
selector
);
return [selection, binder.update] as const;
// optionally set initial data
binder.update((state) =>
state.todos = [];
state.user = name: ‘Guest’, email: ” ;
);
// use in component
function TodoList()
const [todos, update] = useMutativeYjs((s) => s.todos);
const addTodo = (text: string) =>
update((state) =>
state.todos.push(
id: Math.random().toString(),
text,
done: false,
);
);
;
const toggleTodo = (id: string) =>
update((state) =>
const todo = state.todos.find((t) => t.id === id);
if (todo) todo.done = !todo.done;
);
;
// will only rerender when ‘todos’ array changes
return (
<div>
todos.map((todo) => (
<div key=todo.id onClick=() => toggleTodo(todo.id)>
todo.text todo.done ? ‘✓’ : ‘○’
</div>
))
</div>
);
// when done
binder.unbind();
Berintegrasi dengan kerangka kerja lainnya
Sumbangan dipersilakan! Harap kirimkan kode sampel melalui kerangka kerja Vue, Svelte, Angular atau lainnya.
applyJsonArray(dest, source)
Terapkan array JavaScript sederhana ke Y.Array.
import applyJsonArray from 'mutative-yjs';
import * as Y from 'yjs';
const yArray = new Y.Array();
applyJsonArray(yArray, [1, 2, 3, nested: 'object' ]);
applyJsonObject(dest, source)
Terapkan objek JavaScript normal ke Y.Map.
import applyJsonObject from 'mutative-yjs';
import * as Y from 'yjs';
const yMap = new Y.Map();
applyJsonObject(yMap,
key1: 'value1',
key2: nested: 'value' ,
);
type JSONPrimitive = string | number | boolean | null;
type JSONValue = JSONPrimitive | JSONObject | JSONArray;
type JSONObject = [member: string]: JSONValue ;
interface JSONArray extends Array<JSONValue>
type Snapshot = JSONObject | JSONArray;
type UpdateFn<S extends Snapshot> = (draft: S) => void;
type ListenerFn<S extends Snapshot> = (snapshot: S) => void;
type UnsubscribeFn = () => void;
interface Binder<S extends Snapshot>
unbind: () => void;
get: () => S;
update: (fn: UpdateFn<S>) => void;
subscribe: (fn: ListenerFn<S>) => UnsubscribeFn;
interface Options<S extends Snapshot> Y.Array<any>,
patch: Patch,
applyPatch: (target: Y.Map<any>
mutative-yjs Buat jembatan antara struktur data CRDT YJS dan pola pembaruan invarian mutasi:
- inisialisasi: Saat mengikat tipe data YJS, itu membuat snapshot awal
- memperbarui: Saat Anda menelepon
update()mutasi menghasilkan tambalan yang menggambarkan perubahan - Aplikasi Patch: Patch diterapkan pada struktur data YJS, memicu sinkronisasi
- Penanganan acara: Ketika data YJS berubah (lokal atau remote), acara dikonversi kembali ke pembaruan snapshot
- Berbagi Struktur: Hanya menciptakan kembali bagian yang dimodifikasi dari snapshot untuk mempertahankan kesetaraan referensi untuk data yang tidak berubah
- Pembaruan Batch: Satu perubahan ganda
update()Panggilan lebih efisien daripada beberapa panggilan terpisah - Berbagi Struktur: Bagian negara yang tidak berubah mempertahankan kesetaraan referensi, membuat reaksi ulang reaksi efektif
- berdagang: Pembaruan yang dibungkus dalam transaksi YJS untuk kinerja terbaik otomatis
- Berhenti berlangganan: Selalu hubungi
unbind()Bila dilakukan untuk mencegah kebocoran memori
mutative-yjs Menerapkan semantik kolaborasi cerdas untuk melestarikan perubahan beberapa kolaborator:
Penggantian Elemen Array
Saat mengganti elemen array dengan objek, perpustakaan akan mengeksekusi Pembaruan tambahan Alih -alih menghapus + memasukkan:
// If both old and new values are objects
binder.update((state) =>
state.items[0] = ...state.items[0], name: 'Updated' ;
);
// → Updates properties in-place, preserving other collaborators' changes
Ini mencegah masalah “pembaruan yang hilang” yang dibahas dalam YJS #1 yang mendalam.
Perlindungan Pembaruan Loop
Perpustakaan ini menggunakan asal transaksi untuk mencegah pembaruan loop:
const binder = bind(yMap);
binder.subscribe((snapshot) =>
// Safe: won't cause infinite loop
if (snapshot.count < 10)
binder.update((state) =>
state.count++;
);
);
Deteksi referensi melingkar
Perpustakaan mendeteksi dan menolak referensi objek loop:
const circular: any = a: 1 ;
circular.self = circular;
binder.update((state) =>
state.data = circular; // ❌ Throws: "Circular reference detected"
);
Lihat contoh komprehensif file uji, termasuk:
- Pengikatan dan pembaruan dasar
- Operasi array (splicing, dorongan, dll.)
- Pembaruan objek bersarang
- Pemrosesan Langganan
- Aplikasi Patch Kustom
- Skenario kolaboratif
- mutasi:> = 1.0.0
- Yjs:> = 13.0.0
- Naskah:> = 4.5
- node.js:> = 14
Sumbangan dipersilakan! Silakan mengirimkan permintaan tarik.
- Mutasi dengan API variabel – pembaruan invarian yang efektif
- YJS – Kerangka kerja CRDT untuk membangun aplikasi kolaboratif
Perpustakaan menjembatani dua alat yang kuat:
- Yjs Untuk pengeditan kolaboratif berbasis CRD
- mutasi Untuk ergonomi dan pembaruan negara-invarian kinerja-invarian
immer-yjs Terinspirasi https://github.com/sep2/immer-yjs.
mutative-yjs Ini dilisensikan oleh MIT.
rencana pengembangan website
metode pengembangan website
jelaskan beberapa rencana untuk pengembangan website, proses pengembangan website, kekuatan dan kelemahan bisnis pengembangan website
, jasa pengembangan website, tahap pengembangan website, biaya pengembangan website
#Mutan #jmutan #yjs #perpustakaan #untuk #membangun #aplikasi #web #kolaboratif #yjs