Blog

Automerge, queues, web browsers

Posted on May 31, 2026 by Daniel

I'm writing a web app intended to run on my phone when I'm offline, and also reliably sync changes between devices. I'm using the Automerge CRDT library, Rust compiled to webassembly, and some Progressive Web App (PWA) features to make it behave more like a native app. I'd like to see many more applications written this way, but there are many rough edges; I hope these notes help you avoid some of them.

I like a clear separation & interface between CRDT code and DOM, each of which is complex enough on its own. I also like to ensure that DOM updates caused by local changes go through the same code path as changes that originate on other machines. This makes testing easier – less code, and especially less code that requires two machines / processes to test. More in a minute on how this leads me to an Action enum.

Automerge is schemaless. I have a two-pronged approach to enforcing the schema I want:

Read more

Rust & WebAssembly

Posted on February 11, 2023 by Daniel

tldr; The future of Rust webapps is bright; the present is rocky.

My latest side project uses CRDTs to merge changes from multiple clients, while also allowing offline edits & immediate local feedback. The Automerge CRDT library is written in Rust, so I have been learning the ins & outs of working with WebAssembly in the browser.

Bundlers

I’m told that Webpack can be configured to import webassembly files, or JS files that transitively import webassembly, with the same syntax as normal ES6 imports. Unfortunately, I still don’t have the patience to learn to configure Webpack, and I will go to great lengths to avoid it. For last year’s CRDT project that meant using Parcel, which worked great until I tried to import WebAssembly. Alas, Parcel does not support wasm today (Parcel v1 apparently did, and Automerge v0.1 was pure JS, which is how tack works, but for today I want to use the actively developed versions.)

So I’ve been trying something more quixotic – writing my entire client side in Rust, aside from the loading function below. init takes care of fetching & loading the wasm file. I pass the URL of the server in from JS so that I don’t need to recompile the Rust code when deploying.

Read more

Applicatives and Monoids

Posted on October 15, 2019 by Daniel

I’m tinkering with bits of a new Haskell Postgres library. It’s very much not ready for others to use, but I’m using an interesting type, new to me, which I want to share. Maybe someone can point me at prior art, also.

The main idea is that as we build up decoding functions, we want to collect type names at the same time. We’ll use the type names at runtime, to check that Postgres sends what Haskell expects. If not, we’ll use them in an error message.

Read more

Many ways to load modules

Posted on March 7, 2018 by Daniel

I’ve been confused for years by variations of the :load command in GHCi. So much so it often keeps me from using GHCi.

The GHC manual mentions:

That’s a lot of different commands!

Read more