#Building Offline-first apps

1 messages · Page 1 of 1 (latest)

feral fulcrum
#

I did a search and this conversation hasn't happened in a while. I am curious how folks are handling offline-first in Remix. It seems like there was a flurry of questions for a while. Has anyone built any samples they can share. Obviously this is one of the most challenging things to solve. I found a service that makes it super easy... for $500 a month... SO that isn't happening LOL.

I am thinking at this point that react router might be the best option paired with vite just so it can be a pure SPA. I am also thinking of using either Dexie or RxDB as a local DB that syncs data from my regular SQL DB (I am using directus). Really all I need is the catalog to be offline-first, but that is 10,000 items at least that needs to be stored locally.

I would love to hear your thoughts and solutions.

brisk sleet
#

Ooh, I'd be curious to know what that $500/month service is 😅

#

Right now you've not got great options. Remix's loader/action paradigm is geared towards server-rendered apps. You pretty much have to manage all of the offline-first stuff client-side as if you were building a static React app.

#

I migrated a Remix app to be offline-first, and realized Remix was doing me no favors. I swapped it out for Vite + React + React Router.

feral fulcrum
# brisk sleet Right now you've not got great options. Remix's loader/action paradigm is geared...

Yeah! the service for offline-first is https://replicache.dev/. It is really clean looking.

Ok, yeah, that makes a lot of sense. My company had me build with Next.js, but I think that is doing me less favors than Remix would. I am a huge fan of Remix, I have been wanting to build in it forever. But got stuck with Next instead. But with offline first, nothing makes life easy LOL.

Replicache

Replicache is a client-side datastore and sync framework for building local-first web apps. It works with most backend stacks.

brisk sleet
#

Replicache is sick. Are you talking about Reflect for the $500/month service? - Just saw the pricing table. Whew, that's wild.

#

Offline first is still a budding niche, but I'm super interested in it. I think we'll see tools and resources around this more as we push the frontier forward.

frigid spire
brisk sleet
#

For example, Local-first, decentralized auth is something we don't really have on the web yet. It'll be exciting to see developments here.

brisk sleet
frigid spire
#

I wonder how that compares to Dexie cloud?

#

I'm currently using Dexie in a project but it's a pain in the butt, due to the fact that is asynchronous.

brisk sleet
brisk sleet
#

Replicache's API is async, but the experience is just about as fast as sync.

frigid spire
#

IndexedDb is notoriously slow. I'm not sure why I'm having trouble with it.

brisk sleet
#

I've not used Dexie. My understanding is that IndexedDB is great for persistence, but that your read/write model should exist in-memory, so IndexedDB becomes an invisible implementation detail.

frigid spire
#

...like, if I clear the site data and reload the page.

#

It has to fetch the data from the Remix Db, then populate IndexedDb with that data, then use it in the app. The app keeps crashing on the first page load but then works on the second load (reload).

brisk sleet
#

Yup. That's the trick with offline-first. Kinda have to deal with those loading states still.

brisk sleet
#

Ah, I missed that one

#

I'm quite interested to see how the client data proposal shakes out. Looks like it will make this kind of thing much easier, especially after the first load.

frigid spire
#

Yes. That sounds fantastic!

#

I think I'm going to try this out. It looks pretty sweet. I'm trying to understand what it uses for a data store. I don't think it uses IndexedDb which already makes it better than Dexie. Does it just write to the file system or something?

brisk sleet
#

If it's using replicache, then it probably is using IndexdedDB under the hood.

frigid spire
#

Oh. Evidently the File System API is 4x faster.

brisk sleet
#

Legit

frigid spire
feral fulcrum
feral fulcrum
#

Dexie cloud was interesting. to me as well, then the pricing. If you are not locked into a backend, using pouchDB and couchDB would be a great solution. I am stuck with my Directus backend.

knotty raft
#

There might be some prior art in remix PWA you can look at for some of this

https://remix-pwa.run/

The home of Remix PWA. Enhance your Remix application with PWA functionalities like never before.

frigid spire
frigid spire
brisk sleet
frigid spire
#

No response needed.

frigid spire
# brisk sleet Sounds like a good stack for that kind of thing.

I'm not necessarily trying to do an off-line first app... I'm making an audio mixer app that saves any change made (like changing the volume of a track) to IndexedDb on the fly. So it uses that as "source of truth" (not sure if I'm using that term correctly) but it only saves that entire "mix" (all the changes in IndexedDb) to the server when the "Save" button is pressed. So that's the source of truth if the local copy gets erased... So is that considered "off-line first?" Not sure if I'm making sense.

#

I guess it doesn't matter what the terminology is. My main question is, to prevent the loding problems I described earlier in this thread. Do I need to not use Remix?

brisk sleet
#

I don't think Remix is the source of your loading problems.

#

I think you need to find a synchronization mechanism to make it so when the app first starts up, if the local database (IndexedDB) doesn't have the data, it loads that data from the server before loading the app.

And then it needs to synchronize any changes that have happened in the remote database whenver they happen too.

frigid spire
#

In a useEffecthook?

brisk sleet
#

No, it'd need to be more than that.

frigid spire
brisk sleet
#

Hang on, I had to answer a coworkers question. I've got more for you

#

Suppose you've got two clients that are both offline and working on the same audio project, but they do different things. The state has diverged - how do you reconcile it?

CRDTs are one approach, popularized by Y.js and Automerge. Another option is Replicache's atomic transactions approach.

Synchronizing needs to happen between the server and the client, where the client sends updates to the server and the server sends the synchronized, conflict-free state back to the client. Websockets are common for this, but polling works too.

frigid spire
#

Wait. I need to explain this better. It's kinda weird what I'm doing...

The data in IndexedDB is erased and reloaded with new data every time a different mix is loaded or created. That data isn't shared between different users. It's only available to the owner of that mix.

#

But different mixes are saved to the server.

#

Then they load IndexedDb with the data for that mix.

#

When selected in a menu of mixes.

brisk sleet
#

What happens when a user logs on from a different device?

#

I suppose they just download what is already saved to the server?

frigid spire
#

It crashes the first load, then works then second. the way I have I now.

brisk sleet
#

And so if I download from the server, and then another device pushes the save button, and then the first device pushes the save button, the second device's save is overwritten by the first device?

frigid spire
#

Hold on. Let me see.

frigid spire
brisk sleet
#

On the server

frigid spire
#

The data gets overwritten on the server everytime the save button is pushed.

#

no matter what device.

brisk sleet
#

Because allegedly, when the second device loads the page again, it pulls from the server and overwrites what's in IndexedDB, so actually both.

frigid spire
#

But the changes are not reflected on the fly in the second devices UI.

frigid spire
#

If they're mixing something, they wouldn't be switching devices.

brisk sleet
frigid spire
#

Hold on. Let me do some testing. It might take a while. Thanks. I'll get back to you on this.

brisk sleet
#

Sure thing.

frigid spire
#

Would that be the "synchronization mechanism"?

brisk sleet
#

Yup. Something like that.

#

But its your app. Do what you want.

#

If you don't think that kind of conflict resolution stuff is necessary, than it would be overkill