Mutan j/mutan yjs: perpustakaan untuk membangun aplikasi web kolaboratif yjs

 – Beragampengetahuan
9 mins read

Mutan j/mutan yjs: perpustakaan untuk membangun aplikasi web kolaboratif yjs – Beragampengetahuan

Node CI
NPM
lisensi

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();
  1. import bind from 'mutative-yjs'.
  2. Buat perekat: const binder = bind(doc.getMap("state")).
  3. Tambahkan langganan ke snapshot: binder.subscribe(listener).
    1. Mutasi dalam tipe data Y.JS akan memicu langganan snapshot.
    2. Menelepon update(...) (Mirip dengan create(...) Dalam mutasi) akan memperbarui jenis Y.JS yang sesuai dan memicu langganan snapshot.
  4. panggilan binder.get() Untuk mendapatkan snapshot terbaru.
  5. (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 YJS
  • options?: 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 YJS
  • initialState: S – Keadaan awal yang akan ditetapkan
  • options?: 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:

  1. update() Ditelepon
  2. Data YJS dasar telah dimodifikasi

parameter:

  • fn: (snapshot: S) => void – Fungsi panggilan balik untuk menerima snapshot baru
  • options?: SubscribeOptions – Konfigurasi Langganan Opsional
    • immediate?: 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 useSyncExternalStoreWithSelector from ‘use-sync-external-store/with-selector’;
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:

  1. inisialisasi: Saat mengikat tipe data YJS, itu membuat snapshot awal
  2. memperbarui: Saat Anda menelepon update()mutasi menghasilkan tambalan yang menggambarkan perubahan
  3. Aplikasi Patch: Patch diterapkan pada struktur data YJS, memicu sinkronisasi
  4. Penanganan acara: Ketika data YJS berubah (lokal atau remote), acara dikonversi kembali ke pembaruan snapshot
  5. 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

Tinggalkan Balasan

Alamat email Anda tidak akan dipublikasikan. Ruas yang wajib ditandai *