Lokale-First-Architektur für Progressive Web Apps
Service Worker verschieben die App auf das Gerät des Nutzers; Local-First verschiebt die Daten. Genau dieser Unterschied erklärt, warum die Shell Ihrer PWA offline sofort lädt, während jede Liste, jeder Datensatz und jedes Formular noch auf ein fetch() wartet, das in dem Moment fehlschlägt, in dem die Netzwerkverbindung abbricht. Die Shell ist gecacht; die Daten sind es nicht. Sie befinden sich auf unterschiedlichen Ebenen, und die Lücke zwischen ihnen ist der Ort, an dem die meisten PWA-Implementierungen mit „Offline-Unterstützung” stillschweigend versagen.
Dieser Artikel richtet sich an Entwickler, die bereits eine PWA veröffentlicht haben — das Manifest ist valide, der Service Worker cached Assets, die App lässt sich auf dem Startbildschirm installieren — und die vermuten, dass „Local-First” mehr bedeutet als die Offline-First-Arbeit, die sie bereits geleistet haben. Das tut es. Local-First ist eine Datenarchitektur, kein Laufzeitmechanismus. Der Rest dieses Artikels trennt diese Ebenen klar voneinander, zeigt, wie eine Local-First-PWA als Stack aussieht, dem man Schichten hinzufügt, anstatt ihn neu aufzubauen, gibt einen Überblick über die Speicher- und Synchronisierungsoptionen und bietet einen PWA-spezifischen Leitfaden dazu, wann dieses Muster seine Komplexität rechtfertigt.
Wichtigste Erkenntnisse
- Service Worker cachen Assets und stellen die Offline-Shell bereit; Local-First ist eine Datenarchitektur, bei der das Gerät die primäre Kopie der Daten hält und der Server, wenn vorhanden, als Synchronisierungs-Peer statt als Gatekeeper fungiert.
- Eine Local-First-PWA besteht aus drei kombinierbaren Ebenen: einem Service Worker (Assets und Offline-Shell), einer lokalen Datenbank (Lese- und Schreibzugriffe auf Daten) und einer Sync-Engine (letztendliche Konsistenz mit dem Server) — Sie fügen die zweite und dritte Ebene hinzu, ohne die erste zu ersetzen.
- IndexedDB ist die praktische Untergrenze für lokalen Datenspeicher; OPFS-gestütztes SQLite, zu WebAssembly kompiliert, ist die aktuelle Obergrenze und bietet eine vollständige relationale Datenbank im Browser.
- Field-Level Last-Write-Wins löst die Mehrheit der Konflikte in typischen Anwendungen; kollaborative Texteditierung erfordert CRDTs, und semantische Konflikte (zwei Nutzer buchen denselben Raum) erfordern serverseitige Validierung während der Synchronisierung.
- Local-First eignet sich für installierbare Notiz-Apps, Field-Service-Anwendungen und kollaborative Editier-PWAs; es bietet keinen Mehrwert für Dashboards mit servergenerieren Daten oder für alles, was an ACID-Garantien gebunden ist.
Warum die Daten Ihrer PWA noch immer das Netzwerk benötigen
Eine PWA mit gecachter Shell, aber einer von fetch() abhängigen Datenschicht ist nur im engsten Sinne offline-fähig — die Oberfläche lädt ohne Netzwerk, und dann stoppt jede Komponente, die Daten benötigt. Der Service Worker kann HTML, CSS und JavaScript aus der Cache API ohne Netzwerkzugriff wiedergeben, sodass die App offline gerendert wird. Die Daten, die diese Komponenten anzeigen, kommen jedoch weiterhin aus einer Netzwerkanfrage, und ein ServiceWorker, der ein fetch() für dynamische Nutzerdaten abfängt, hat nichts Sinnvolles zurückzugeben, wenn diese Daten noch nie gecacht wurden oder sich seit dem letzten Caching geändert haben.
Das ist der strukturelle Grund, warum Offline-First-PWA-Arbeit an der Shell aufhört. Caching-Strategien — Cache-First, Network-First, Stale-While-Revalidate — sind Antworten auf die Frage, welche Version eines Assets bereitgestellt werden soll und wie veraltet sie sein darf. Sie sind keine Antworten auf die Frage, wo die Daten des Nutzers liegen und wer die autoritative Kopie besitzt. Die Cache API speichert HTTP-Antworten, die durch Anfragen indiziert sind. Sie ist keine Datenbank, die man abfragen, in die man schreiben und aus der man innerhalb einer Komponente lesen kann. Um die Lücke zu schließen, benötigen Sie einen tatsächlichen lokalen Datenspeicher und eine Strategie, um ihn konsistent mit dem Server zu halten. Das ist Local-First.
Local-First ist nicht Offline-First, und keines von beidem ist ein Service Worker
Local-First, Offline-First, PWA und Service-Worker-Caching sind vier verschiedene Konzepte, die sich kombinieren lassen, aber nicht austauschbar sind. Sie zu verwechseln ist die häufigste Quelle von Verwirrung in diesem Bereich.
| Begriff | Was es ist | Auf welcher Ebene es operiert |
|---|---|---|
| PWA | Ein Auslieferungsmodell: installierbare, manifest-gesteuerte, push-fähige Web-App | Paketierung |
| Service Worker | Ein Laufzeitmechanismus, der Anfragen abfängt und gecachte Assets bereitstellt | Netzwerk / Laufzeit |
| Offline-First | Ein Designziel: graceful degradation bei Netzwerkausfall, wobei der Server weiterhin die Source of Truth bleibt | Verhalten |
| Local-First | Eine Datenarchitektur: das Gerät hält die primäre Kopie; der Server ist ein Synchronisierungs-Peer | Daten |
Offline-First bedeutet, dass die Anwendung Netzwerkausfälle graceful behandelt, der Server aber weiterhin die Source of Truth bleibt — der lokale Cache ist eine Komfortkopie, die dem Remote-Stand untergeordnet ist. Local-First kehrt diese Beziehung um: Das Gerät des Nutzers hält die primäre Kopie der Daten, die Anwendung liest und schreibt in eine lokale Datenbank, und der Server ist, wenn vorhanden, einer von mehreren Knoten, die im Hintergrund abgeglichen werden. Die klare Trennung ist wichtig, weil sie Ihnen zeigt, was Sie wiederverwenden können. Ihr Service Worker und Ihr Framework ändern sich nicht. Sie fügen darunter eine Datenschicht hinzu.
Plainvanilla’s Local-First-Walkthrough bündelt das Backend-for-Frontend als Teil der Architektur in den Service Worker. Das ist eine mögliche Implementierung, nicht die Definition. Halten Sie die Ebenen getrennt: Local-First betrifft den Ort, an dem Daten liegen und welche Kopie autoritativ ist; der Service Worker ist ein Mechanismus, der zufällig in derselben Laufzeitumgebung verfügbar ist.
Discover how at OpenReplay.com.
Was Local-First tatsächlich bedeutet
Local-First ist eine Datenarchitektur, bei der das Gerät des Nutzers die primäre Kopie der Anwendungsdaten hält, die App in eine lokale Datenbank liest und schreibt, und der Server, wenn vorhanden, ein Synchronisierungs-Peer mit besonderer Autorität ist, anstatt ein Gatekeeper, der jeden Lese- und Schreibzugriff genehmigen muss. Die Anwendung liest aus einer lokalen Datenbank und schreibt in sie — aus Sicht des Nutzers synchron — und die Synchronisierung mit dem Server oder anderen Geräten erfolgt asynchron im Hintergrund. Die architektonische Verschiebung ist eine Neuklassifizierung des Clients: Er hört auf, eine dünne Ansicht zu sein, die um Erlaubnis bittet, Daten anzuzeigen, und wird zu einem vollwertigen Teilnehmer, der ein Replikat besitzt.
Die kanonische Referenz ist der Essay aus dem Jahr 2019 Local-First Software: You Own Your Data, in Spite of the Cloud von Ink & Switch, der sieben Ideale darlegt — schnell, multi-device-fähig, offline-tauglich, kollaborativ, langlebig, privat und nutzerkontrolliert. Die einzige Eigenschaft, die verändert, wie man Code schreibt, ist die erste: Da Lese- und Schreibzugriffe auf eine lokale Datenbank gehen, gibt es kein isLoading-Flag bei einem Lesevorgang, und Schreibvorgänge können den lokalen Zustand sofort aktualisieren. Der lokale Schreibvorgang ist der Zustand, während Synchronisierung und Konfliktlösung im Hintergrund stattfinden.
Im Komponentencode reduziert das einen Fetch-und-Cache-Ablauf auf eine direkte Abfrage. Anstatt eines useQuery, das { data, isLoading, error } zurückgibt, abonniert eine Local-First-Abfrage die lokale Datenbank und rendert neu, wenn sie sich ändert:
// Local-first: the query reads the local DB and re-renders on change.
// No isLoading, no error boundary for the read, no cache invalidation.
function TaskList({ projectId }) {
const tasks = useLiveTasks(projectId); // subscribes to local DB
return (
<ul>
{tasks.map((t) => (
<li key={t.id}>{t.title}</li>
))}
</ul>
);
}
Der useLiveTasks-Hook wird von der Sync-Engine oder Query-Schicht Ihrer Wahl bereitgestellt; die Form ist das Entscheidende. Ein Schreibvorgang ist ein einfaches Insert gegen den lokalen Store, das Abonnement wird ausgelöst, und die UI aktualisiert sich. Die Synchronisierung mit dem Server erfolgt, wann immer das Netzwerk es erlaubt.
Die drei Ebenen einer Local-First-PWA
Eine Local-First-PWA besteht aus drei kombinierbaren Ebenen: einem Service Worker, der Assets cached und die Offline-Shell bereitstellt, einer lokalen Datenbank (IndexedDB oder OPFS-gestütztes SQLite), die die Daten des Nutzers hält und alle Lese- und Schreibzugriffe bedient, sowie einer Sync-Engine, die die lokale Datenbank im Hintergrund mit dem Server abgleicht. Jede Ebene ist für einen Aspekt zuständig und kennt die internen Details der anderen nicht.
| Ebene | Rolle | Verantwortlich für | NICHT verantwortlich für |
|---|---|---|---|
| Ebene 3 — Sync-Engine | Gleicht die lokale Datenbank mit dem Server ab. | Konfliktlösung, letztendliche Konsistenz, Hintergrund-Push/Pull. | Rendering, Asset-Caching. |
| Ebene 2 — Lokale Datenbank | Hält die Daten des Nutzers. IndexedDB oder OPFS-gestütztes SQLite (WASM). | Alle Lese- und Schreibzugriffe, die die UI durchführt. | Das Netzwerk, die Offline-Shell. |
| Ebene 1 — Service Worker | Cached Assets und stellt die Offline-Shell bereit. | Caching von Assets, Bereitstellung der Offline-Shell, Install/Activate-Lifecycle, Push. | Nutzerdaten. |
Die Einführung von Local-First in eine bestehende PWA erfordert nicht, den Service Worker oder das Anwendungs-Framework zu ersetzen — es erfordert das Hinzufügen einer Datenschicht, aus der die Anwendung lokal liest und in die sie schreibt, sowie einer Sync-Engine, die diese Schicht konsistent mit dem Server hält. Ebene 1 existiert bereits in Ihrer PWA. Sie führen Ebene 2 und 3 unterhalb der Komponenten ein, die derzeit fetch() aufrufen, und verdrahten diese Komponenten neu, sodass sie stattdessen aus der lokalen Datenbank lesen.
Wo die Daten liegen: Ein Überblick über lokalen Speicher
localStorage ist nicht die Antwort. Es ist synchron und blockiert damit den Main Thread; es speichert nur Strings; und laut der MDN Web Storage API-Dokumentation ist seine Kapazität gering und browserspezifisch — geeignet für eine Theme-Präferenz, ungeeignet für eine Datenschicht.
IndexedDB ist die Untergrenze — asynchron, in jedem modernen Browser verfügbar und in der Lage, weit mehr als localStorage zu speichern, wobei das Speicherkontingent ursprungsbasiert und browserspezifisch ist und keine feste Obergrenze darstellt. Die native API ist low-level und ausführlich — ein einzelner Schreibvorgang erfordert das Öffnen einer Transaktion, die Adressierung eines Object Stores und die Verkabelung von Request-Callbacks — weshalb die meisten Anwendungen auf eine Abstraktionsschicht zurückgreifen.
Die Obergrenze ist SQLite, zu WebAssembly kompiliert und im Origin Private File System (OPFS) persistiert. OPFS-gestütztes SQLite bietet eine vollständige relationale Datenbank im Browser — Transaktionen, Indizes und eine vertraute SQL-Schnittstelle, die lokal auf dem Client läuft. OPFS unterstützt hochperformanten synchronen Dateizugriff über createSyncAccessHandle(), das nur innerhalb eines Web Workers verfügbar ist — genau das Zugriffsmuster, das SQLite benötigt. Die offizielle SQLite WebAssembly-Distribution dokumentiert OPFS als unterstütztes Persistenz-Backend.
Im Code liest sich ein Schreibvorgang gegen SQLite-over-WASM wie serverseitiges SQL — eine einzelne Anweisung gegen einen relationalen Store:
// SQLite (WASM) via the official sqlite-wasm package: ordinary SQL.
await db.exec({
sql: "INSERT INTO tasks (id, title, done) VALUES (?, ?, 0)",
bind: [crypto.randomUUID(), "Review draft"],
});
Die Browserunterstützung für OPFS ist Stand Ende 2025 breit — siehe die MDN-Kompatibilitätstabelle für die File System API für den aktuellen browserspezifischen Status, der die maßgebliche Referenz für Ihre Support-Matrix ist und nicht als fest kodierte Versionsliste, da sie sich ändert. Ein häufiger Fallstrick in der Produktion ist, dass das OPFS-Verhalten zwischen Browser-Engines und Einbettungskontexten subtil variieren kann. Daher lohnt es sich, einen IndexedDB-basierten Fallback-Pfad für Browser und Umgebungen beizubehalten, in denen OPFS-Unterstützung nicht verfügbar, eingeschränkt oder anders als auf Ihrer primären Zielplattform ist.
Die Landschaft der Sync-Engines
Die Sync-Engine ist die Schicht, die Local-First zu mehr als Offline-First macht: Sie gleicht das lokale Replikat mit dem Server und anderen Geräten ab. Sie müssen sie nicht selbst bauen. Mehrere produktionsreife und aufkommende Engines besetzen unterschiedliche Nischen, und die richtige hängt von der Form Ihrer App und Ihrem bestehenden Backend ab. Es gibt keinen Webstandard für Synchronisierung, daher definiert jede Engine ihr eigenes Protokoll — halten Sie die Sync-Schicht abstrahiert, damit ein Wechsel der Engine machbar bleibt.
- PowerSync — repliziert ein Postgres-Backend in eine Client-SQLite-Datenbank mit einem Write-Back-Pfad; besonders geeignet, wenn Sie bereits Postgres betreiben und Offline-Unterstützung ohne Neuarchitektur des Servers wünschen.
- Electric — eine Postgres-Sync-Engine, die auf „Shapes” basiert, die definieren, welche Daten jeder Client erhält. Besonders geeignet für Anwendungen, die partielle Replikation und benutzerspezifische Datensynchronisierung auf einem bestehenden Postgres-Backend benötigen.
- Replicache und Zero (beide von Rocicorp) — abfragegesteuerte Sync-Systeme, die lokale-First-Nutzererfahrungen gegenüber zeilenbasierter Replikation priorisieren. Besonders geeignet für Anwendungen, die auf clientseitigen Mutationen, optimistischen Updates und serverseitiger Reconciliation basieren.
- Triplit — eine Full-Stack-Datenbank mit integrierter Synchronisierung, sodass Client- und Server-Datenbank ein einheitliches mentales Modell bilden statt zwei; geeignet für Greenfield-Apps, die Sync als Standard wünschen.
- Yjs und Automerge — CRDT-Bibliotheken für kollaborative Editierung; die richtige Wahl, wenn mehrere Nutzer denselben Rich-Text oder dasselbe strukturierte Dokument gleichzeitig bearbeiten und Sie ein Merge auf Zeichenebene benötigen.
Für die meisten geschäftlichen PWAs, die nutzereigene Datensätze synchronisieren, ist eine zeilenbasierte Replikations-Engine über Ihrer bestehenden Datenbank ein besserer Fit als eine CRDT-Bibliothek. Greifen Sie auf Yjs oder Automerge zurück, wenn kollaborative Echtzeit-Texteditierung das eigentliche Produkt ist, nicht als allgemeine Konfliktlösungsstrategie.
Konflikte lösen
Wenn zwei Replikate dieselben Daten modifizieren, ohne die Änderungen des jeweils anderen gesehen zu haben, muss die Sync-Engine sie abgleichen. Konflikte lassen sich in drei Kategorien einteilen, jede mit einer anderen Lösungsstrategie.
-
Strukturelle Konflikte — Field-Level Last-Write-Wins. Field-Level Last-Write-Wins behandelt die Mehrheit der Konflikte in typischen Anwendungen: Wenn zwei Nutzer offline verschiedene Felder desselben Datensatzes bearbeiten, bleiben beide Änderungen erhalten; wenn sie dasselbe Feld bearbeiten, gewinnt der spätere Zeitstempel. Dies ist eine in der Local-First-Community weit verbreitete Faustregel, kein gemessener Konstantwert — Martin Kleppmanns Designing Data-Intensive Applications behandelt die Konsistenz-Tradeoffs von Last-Write-Wins ausführlich.
-
Kollaborative Textkonflikte — CRDTs. Wenn zwei Nutzer in denselben Absatz tippen, verwirft Last-Write-Wins die Tastenanschläge einer Person. Conflict-Free Replicated Data Types führen gleichzeitige Bearbeitungen auf Zeichenebene zusammen, sodass beide Zeichensätze kohärent erscheinen. Yjs und Automerge implementieren dies; die Merge-Mechanismen unterscheiden sich, aber die Garantie ist dieselbe — gleichzeitige Bearbeitungen konvergieren ohne einen zentralen Koordinator.
-
Semantische Konflikte — serverseitige Validierung. Einige Konflikte lassen sich auf struktureller Ebene sauber zusammenführen, erzeugen aber ein Ergebnis, das eine fachliche Invariante verletzt. Beispiel: Zwei offline arbeitende Nutzer buchen denselben Besprechungsraum für 14 Uhr. Beide Schreibvorgänge zielen auf verschiedene Datensätze, sodass ein Field-Level-Merge beide akzeptiert — strukturell korrekt, aber eine Doppelbuchung. Semantische Konflikte, bei denen die Daten sauber zusammengeführt werden, das Ergebnis aber eine fachliche Invariante verletzt, erfordern serverseitige Validierung während der Synchronisierung. Das Muster, das Datenverlust vermeidet, besteht darin, den konfliktierenden Schreibvorgang zu akzeptieren, die Verletzung zu kennzeichnen und sie dem Nutzer als lösbare Benachrichtigung anzuzeigen, anstatt sie stillschweigend abzulehnen — eine Ablehnung hinterlässt auf dem Client Datensätze, die der Server nicht anerkennen will.
Die schwierigsten Bugs in Local-First-PWAs sind keine Sync-Fehler — diese tauchen in Logs auf. Es sind stille Überschreibungen: Ein optimistischer Schreibvorgang gelingt lokal, die Synchronisierung wird ohne Fehler abgeschlossen, und die Änderung des Nutzers wird stillschweigend durch eine Remote-Version ersetzt, die das Last-Write-Wins-Rennen gewonnen hat. Der Fehler ist für Server-Logs, Error-Monitoring und Netzwerk-Traces unsichtbar; er wird nur in einem Tool erkennbar, das die Abfolge von UI-Zuständen aufzeichnet — das optimistische Update und die stille Rücknahme, die folgt. Session-Replay ist einer der wenigen Orte, an dem diese Diskrepanz als nachvollziehbare Abfolge sichtbar wird, anstatt als saubere Log-Zeile.
Wann Local-First zu Ihrer PWA passt
Local-First passt zu einer PWA, wenn die von der App verwalteten Daten dem Nutzer gehören und von sofortiger lokaler Interaktion profitieren; es bietet keinen Mehrwert, wenn die Daten vom Server generiert werden oder an starke Transaktionsgarantien gebunden sind. Die entscheidende Frage ist nicht die App-Kategorie im Allgemeinen — es ist die Frage, ob die Daten auf das Gerät gehören.
| PWA-Anwendungsfall | Hilft Local-First? | Warum |
|---|---|---|
| Installierbare Notiz-App | Ja | Nutzereigene Daten, sofortige Lese-/Schreibzugriffe, Offline-Editierung ist der Kernwert; die installierbare Shell und lokale Daten verstärken sich gegenseitig. |
| Field-Service-App bei unzuverlässiger Konnektivität | Ja | Die Arbeit findet dort statt, wo das Netzwerk schwach ist; Schreibvorgänge müssen offline gelingen und synchronisiert werden, wenn wieder Empfang besteht. |
| Kollaboratives Editierwerkzeug | Ja | Gleichzeitiges Editieren ist das Produkt; CRDT-gestützter Sync ermöglicht Echtzeit-Merge ohne einen Roundtrip pro Tastenanschlag. |
| Analytics-Dashboard | Nein | Der Server generiert die Daten; das Cachen der Shell ist nützlich, aber Local-First bietet keinen Mehrwert für Daten, die der Nutzer nicht besitzt oder verändert. |
| E-Commerce-Checkout | Nein | Zahlung und Inventar benötigen ACID-Garantien und eine einzige autoritative Datenbank; letztendliche Konsistenz kann Lagerbestände überverkaufen oder doppelt belasten. |
| Social Feed | Nein | Der Feed wird serverseitig gerankt und ist serverseitig verwaltet; der Client konsumiert ihn, anstatt ihn zu erstellen. |
Das Muster passt genau dort zu den Stärken von PWAs, wo der Nutzer die Daten erstellt und besitzt. Bei einer Notiz-PWA komponieren sich die installierbare Shell, der Offline-Schreibvorgang und die Hintergrundsynchronisierung zu einer Erfahrung, die einer nativen App nahekommt. Bei einem Dashboard kann der Service Worker die Shell für schnelleres Laden cachen, aber die Zahlen kommen weiterhin vom Server — Local-First löst ein Problem, das dieser Anwendungsfall nicht hat.
Sie fügen eine Datenschicht hinzu, Sie bauen die App nicht neu
Die nachträgliche Einführung von Local-First in eine bestehende PWA bedeutet, zwei Ebenen hinzuzufügen, nicht das Vorhandene neu aufzubauen: eine lokale Datenbank und eine Sync-Engine-Schicht unterhalb der Komponenten, die derzeit auf fetch() warten, während Service Worker und Framework an ihrem Platz bleiben. Sie ersetzen nicht die PWA-Arbeit, die Sie bereits geleistet haben — Sie vervollständigen sie und verschieben die Daten zum Nutzer, so wie der Service Worker bereits die App verschoben hat. Der konkrete nächste Schritt ist klein: Wählen Sie ein Feature, dessen Daten dem Nutzer gehören und das er bearbeitet, stützen Sie es auf IndexedDB oder OPFS-gestütztes SQLite, verdrahten Sie seine Komponente so, dass sie aus diesem Store liest, und lassen Sie eine Sync-Engine es im Hintergrund abgleichen. Dieses einzelne Feature wird Ihnen schneller als jede weitere Lektüre zeigen, ob der Rest Ihrer App dorthin gehört.
FAQs
Meistens ja, aber seine Rolle ändert sich. In einer Local-First-Architektur hört der Server auf, ein Gatekeeper zu sein, der jeden Lese- und Schreibzugriff genehmigt, und wird zu einem Synchronisierungs-Peer, der die lokale Datenbank geräteübergreifend abgleicht, eine dauerhafte Kopie persistiert und serverseitige Validierung für semantische Konflikte wie Doppelbuchungen durchsetzt. Apps, die ACID-Garantien, Zahlungen oder autoritativen gemeinsamen Zustand benötigen, erfordern weiterhin ein echtes Backend; nur der Lese- und Schreibpfad durch die UI wechselt zur lokalen Datenbank.
Nein. Sie operieren auf unterschiedlichen Ebenen und ergänzen sich, anstatt zu konkurrieren. Der Service Worker cached Assets und stellt die Offline-Shell bereit; Local-First fügt eine lokale Datenbank und eine Sync-Engine unterhalb der Komponenten hinzu, die derzeit fetch aufrufen. Die nachträgliche Einführung von Local-First in eine bestehende PWA bedeutet, Service Worker und Framework an ihrem Platz zu lassen und die Daten- und Sync-Schichten darunter einzuführen, nicht Ebene 1 neu zu schreiben.
Wählen Sie CRDTs, wenn das gleichzeitige Editieren desselben Rich-Texts oder strukturierten Dokuments das eigentliche Produkt ist, denn Last-Write-Wins verwirft die Tastenanschläge eines Nutzers, wenn zwei Personen in denselben Absatz tippen. Conflict-Free Replicated Data Types führen gleichzeitige Bearbeitungen auf Zeichenebene zusammen, sodass beide Zeichensätze ohne einen zentralen Koordinator konvergieren. Für die meisten geschäftlichen PWAs, die nutzereigene Datensätze synchronisieren, ist Field-Level Last-Write-Wins über einer zeilenbasierten Replikations-Engine der bessere Fit; reservieren Sie Yjs oder Automerge für kollaborative Echtzeit-Texteditierung.
Das ist eine stille Überschreibung. Ein optimistischer Schreibvorgang gelingt lokal, die Synchronisierung wird ohne Fehler abgeschlossen, und eine Remote-Version gewinnt das Last-Write-Wins-Rennen und ersetzt stillschweigend die lokale Änderung. Der Fehler ist für Server-Logs, die Erfolg melden, für Error-Monitoring, das keine Ausnahme wirft, und für Netzwerk-Traces, die zeigen, dass die Anfrage durchgegangen ist, unsichtbar. Er wird nur in einem Tool erkennbar, das die Abfolge von UI-Zuständen aufzeichnet und sowohl das optimistische Update als auch die darauffolgende Rücknahme erfasst.
Understand every bug
Uncover frustrations, understand bugs and fix slowdowns like never before with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data. Check our GitHub repo and join the thousands of developers in our community.