# Offline-first
Right - we have a real-time application running, but how do we get our application to be offline-first? Well, it is very simple - in fact so simple it ought to be illegal!
First we have to import the necessary wrappers; one for the client and one for the server.
For the server we do this
Now restart the server and refresh the client in the browser and that's it! From now on, all activity on the messages
service on the client will be handled in a client-first server-later (possibly very shortly after) manner. What's more, whenever the client has a valid connection to the server it will synchronize all changes made on the message
service while offline - regardless of the origin of the changes.
Synchronization is done in a newest change wins
manner. Changing the same (same uuid
) item on three different offline devices makes the latest change eventually become the winner.
Items removed from the server cannot be revived (this is because we make a 'soft-delete' on the server to be able to ensure synchronization can be successful at all times).
Note: For this to work you must ensure the service implements the date fields
updatedAt,
onServerAt,
and the id fielduuid.
The wrapper will do all handling of the fields behind the scenes. (Theuuid
do not have to be the id field but it is considered good practice). You can rename these fields if you want (see Offline-first API).For MongoDB you do not have to worry, but for schema-centric DBs you have to ensure your schema include these fields.
Note: If you want to know more about how the wrappers work read own-data/own-net implementation.
# Come-on, it can't be that simple!
Well, it almost is due to Feathers clever adapter implementation. All CRUD service adapters, that are able to pass the adapterTests, should be able work seamlessly with the realtime wrappers. But, you have to choose the wrapper to use based on your needs:
My need | own-data | own-net | Comment |
---|---|---|---|
Keep my data in sync | (✔️) | ✔️ | own-net is less chatty |
Every operation should be available to hooks | ✔️ | ❌ | the only choice |
Only accumulated operations needed for hooks | ❌ | ✔️ | own-net is less chatty |
Furthermore, you need to decide how frequent you want the automatic synchronization to be performed (default is every 24 hours).
Last, you might consider if your application needs to synchronize outside the automatic synchronization and if that's the case you have to make sure you activate the method (with the right options, see FeathersJS Offline-first API).
Note: The realtime wrappers are meant to be used as wrappers for database adapters and will therefore not accept
app.service(<path>).update(id, ...)
withid === null
. You have to usepatch
to alter several documents at the same time.
Tip: You should use the
own-data
/own-net
wrappers with some care, as they consume parts of the browsers storage (either WebSQL, IndexedDB, or localStorage) which is not an unlimited resource pool.
Tip: If you want to take advantage of the
own-data
/own-net
for your server backends, then you must include alocalStorage
solution before you include@feathersjs-offline/client
like:let LocalStorage = require('node-localstorage').LocalStorage; global.localStorage = new LocalStorage('./.scratch');
and of cause use
@feathersjs-offline/server
for the master server.
# What's next?
In the final chapter, we'll look at how to write automated tests for our API. Alternatively, you can digress a read about how Feathers Offline-first has been implemented.