Peter Mbanugoes un desarrollador de software con experiencia trabajando con Microsoft .NET. Es un apasionado de la creación de software de calidad, con intereses en torno a las aplicaciones fuera de línea y la arquitectura de software.
Primero fuera de línea es un enfoque del desarrollo de software distinto del tradicional, en el que la falta de conexión a la red se trata como un error, lo que afecta a la experiencia general del usuario. Con el enfoque "offline-first", se empieza con el entorno más restringido y luego se responde a la experiencia de usuario de la aplicación mejorándola progresivamente a medida que las funcionalidades están disponibles. Para offline-first, se asume que la falta de conexión a la red crea una experiencia de usuario insatisfactoria; por lo tanto, offline-first busca proporcionar la mejor experiencia de usuario posible en todas las condiciones.
El enfoque offline-first viene con algunas preocupaciones tales como, cómo almacenar datos o gestionar transacciones cuando se está offline y sincronizarlo con el servidor, cómo mantener los datos offline seguros, o cómo resolver conflictos de datos si dos usuarios hacen cambios en el mismo registro mientras están offline, etc. Para este post, vamos a ver el almacenamiento de datos sin conexión y la sincronización mediante la construcción de una aplicación web agenda para almacenar los contactos.
Creación de la aplicación de ejemplo
Nuestra aplicación de ejemplo será una aplicación web que se construirá con Bootstrap, jQuery, PouchDB y Couchbase Sync Gateway. Para empezar, vamos a diseñar la página, que incluirá un formulario para introducir el nombre del contacto, correo electrónico y teléfono, y también mostrará una lista de contactos guardados.
Disposición de la página
Cree una carpeta para la aplicación y, a continuación, descargue arranque y jQuery. Descomprime los archivos y colócalos en una nueva carpeta llamada activo
. Añade un nuevo archivo llamado index.html
a su carpeta raíz y copie el siguiente fragmento en ella.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
!DOCTYPE html> <html lang="es"> <head> <meta conjunto de caracteres="utf-8"> <enlace rel="hoja de estilo" href="assets/bootstrap/bootstrap.min.css"> </head> <body> <nav clase="navbar navbar-default"> <div clase="contenedor-fluido"> <div clase="navbar-header"> <a clase="navbar-brand" href="#"> Agenda</a> </div> </div> </nav> <div clase="contenedor"> <div clase="fila"> <div clase="col-md-10"> <h2>Añadir nuevo contacto </h2> <hr /> <form id="contactForm" clase="forma-horizontal"> <div clase="forma-grupo"> <label para="nombre" clase="col-sm-2 control-label">Nombre <div clase="col-sm-10"> <input tipo="texto" clase="control-forma" id="nombre" marcador de posición="Nombre"> </div> </div> <div clase="forma-grupo"> <label para="móvil" clase="col-sm-2 control-label">Móvil <div clase="col-sm-10"> <input tipo="texto" clase="control-forma" id="móvil" marcador de posición="Móvil"> </div> </div> <div clase="forma-grupo"> <label para="email" clase="col-sm-2 control-label">Correo electrónico <div clase="col-sm-10"> <input tipo="email" clase="control-forma" id="email" marcador de posición="Email"> </div> </div> <div clase="forma-grupo"> <div clase="col-sm-offset-2 col-sm-10"> <botón tipo="enviar" clase="btn btn-default">Guardar contacto </div> </div> </form> <hr /> </div> </div> <div clase="fila"> <div clase="col-md-10"> <h2>Lista de contactos</h2> <hr /> <tabla id="contactList" clase="table table-bordered"> <thead> <tr> <th>Nombre</th> <th>Móvil</th> <th>Correo electrónico</th> <th></th> </tr> </thead> <tbody> </tbody> </table> </div> </div> <script src="assets/jquery-2.1.0.min.js"></script> <script src="assets/bootstrap/bootstrap.min.js"></script> </body> </html> |
Lo que tenemos es una página con un formulario para introducir y guardar contactos, y también mostrar la lista de contactos guardados
Acceso/almacenamiento de datos sin conexión
Los datos se convierten en una de las principales preocupaciones de una aplicación Offline-First. Cualquier aplicación que funcione offline tiene que lidiar con el acceso y almacenamiento de datos offline, que se gestionará almacenando los datos en el cliente, y lidiando con el problema de sincronizar los datos de forma fiable. Existen varias bases de datos del lado del cliente para aplicaciones móviles y web, incluyendo Couchbase Lite y Cloudant Sync para clientes móviles y de escritorio, e IndexedDB y Web SQL para navegadores. Para nuestro ejemplo utilizaremos PouchDB, una API de base de datos del lado del cliente en JavaScript que sigue el modelo de la API de CouchDB. PouchDB abstrae las diferentes bases de datos soportadas por los navegadores y sus diferentes interfaces de programación. Fue creada para ayudar a construir aplicaciones que funcionen tan bien offline como online, almacenando los datos localmente mientras se está offline y sincronizándolos con el servidor y otros clientes conectados cuando se está online.
También utilizaré tienda-cliente de sudaderas, un plugin de PouchDB para la persistencia de datos y la sincronización offline. Prefiero trabajar con esta librería por la API disponible para trabajar con datos y sincronización. Añade automáticamente timestamps cuando añado nuevos datos. Añadiré este plugin así como PouchDB usando el npm con el siguiente comando o descargándolo desde aquí tienda-cliente & BolsaBD. Tenga en cuenta que estoy usando PouchDB 6.1.2 y hoodie-store-client 7.0.1.
1 2 3 |
npm instale --guardar pouchdb npm instale --guardar @sudadera/tienda-cliente |
Ahora incluye estos archivos en la página.
1 2 |
Una vez hecho esto, añadimos un nuevo archivo llamado index.js
en el activo
y añadimos un enlace a este archivo en la página. Dentro de este archivo, lo primero que hacemos es inicializar un objeto Store con el nombre de la base de datos y la URL al servidor para la sincronización.
1 2 3 |
$(función(){ var tienda = nuevo Tienda(ejemplo, { remoto: http://localhost:4984/example, PouchDB: PouchDB }); }); |
Añade el siguiente código para guardar el valor introducido en el formulario y añadirlo también a la lista de contactos de la página.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
$(#contactForm).enviar(función(evento) { evento.preventDefault(); var nombre = $(#name).val(); var correo electrónico = $(1TP5Correo electrónico).val(); var móvil = $(1TP5Móvil).val(); // Guardar el contacto en la base de datos tienda.añada({ nombre: nombre, móvil: móvil, correo electrónico: correo electrónico }); $(#contactForm)[0].reiniciar(); }); //añadir nuevo contacto a la página función addNewContactToList(póngase en contacto con) { var nuevoContacto = '' + póngase en contacto con.nombre + '' + póngase en contacto con.móvil + '' + póngase en contacto con.correo electrónico + ' |
' $("#contactList tbody").append(newContact); } //cuando se añade una nueva entrada a la base de datos, ejecuta la función correspondiente store.on('add', addNewContactToList); function loadContacts() { store.findAll().then(function(contacts) { var tbody = "; $.each(contacts, function (i, contact) { var row = '
1 2 |
' + contact.name + '' + contact.mobile + '' + contact.email + ' |
'; tbody += row; }); $("#contactList tbody").html(").html(tbody); }); } // cuando el sitio se carga en el navegador, // cargamos todos los contactos guardados previamente desde hoodie loadContacts();
1 |
Utilicé almacenar.añadir
para insertar en la base de datos local, y luego escuchar los eventos utilizando store.on
en particular el añada
y esto será útil cuando empecemos a sincronizar datos y mostrará nuevos datos después de una sincronización completa con bases de datos remotas. También he añadido una función para mostrar los datos locales cuando la página se carga o se actualiza. Podemos comprobar que podemos guardar los datos localmente.
Ahora tenemos acceso/almacenamiento de datos offline funcionando. Con lo que hemos hecho hasta ahora, deberías empezar a ver el cambio de mentalidad o proceso de pensamiento. Esto es almacenar los datos localmente primero, y después empujar los cambios al servidor cuando esté online. Nuestro siguiente paso es sincronizar estos datos con un servidor Couchbase. Para que esto funcione, necesitamos Couchbase Sync Gateway.
Pasarela de sincronización
Sync Gateway es una aplicación web segura con APIs de sincronización, REST, stream, batch y eventos para acceder y sincronizar datos a través de la web. Sync Gateway permite, entre otras cosas, la replicación segura de datos entre Couchbase Server y
Couchbase Lite y/o PouchDB. Para una guía rápida sobre cómo instalarlo, consulta esto guía. Si Sync Gateway está instalado, será accesible desde el http://localhost:4984
cuando se inicia. Si recuerdas, teníamos una url similar al inicializar el Tienda
para utilizar PouchDB pero con un objeto adicional /ejemplo
como apéndice. El apéndice extra especifica el nombre de la base de datos con la que sincronizamos. Para que nuestra aplicación utilice el almacenamiento y la sincronización de datos sin conexión, iniciemos el servicio Sync Gateway y actualicemos el JavaScript de la página para la sincronización automática. Utilizaré la configuración de Sync Gateway.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
{ "log":["*"], "bases de datos": { "ejemplo": { "servidor":"morsa:", "usuarios": { "INVITADO": { "desactivado": falso, "admin_canales": ["*"] } } } }, "CORS": { "Origen": ["http://127.0.0.1:8801"], "LoginOrigin": ["http://127.0.0.1:8801"], "Cabeceras": ["Tipo de contenido"], "MaxAge": 17280000 } } |
Tenemos una configuración básica que establecerá una conexión con la base de datos de ejemplo y utilizará la opción de almacenamiento en memoria (walrus), que en producción deberíamos cambiar para que apunte a un servidor Couchbase. También hemos añadido la configuración para permitir compartir recursos entre orígenes para nuestra aplicación que está en un puerto diferente. Ahora tenemos que iniciar el servicio Sync Gateway ejecutando el siguiente comando en el terminal
$ ./bin/sync_gateway my-config/phonebook-config.json
Con Sync Gateway iniciado tenemos que actualizar el código para la sincronización continua. Añada el siguiente código a index.js
1 |
tienda.conecte(); |
El código anterior utiliza la tienda de sudaderas conecte
para decirle a PouchDB que inicie una replicación continua con la base de datos remota. Una vez que recargamos nuestra base de datos, los datos que agregamos en el paso anterior se sincronizarán automáticamente con el servidor. Puedes ver esto usando la URL de administración de Sync Gateway http://localhost:4985/_admin/db/example.
Resumen
Con todo lo que tenemos ahora, la aplicación funciona bien con el almacenamiento de datos sin conexión y la sincronización entre dispositivos en tiempo real. Dado que tenemos una aplicación web y los usuarios probablemente abrirán la página cuando estén desconectados o con una conexión inestable, podemos hacer que la página se cargue durante estas situaciones e incluso que se cargue rápidamente utilizando Service Worker, Cache API y Fetch API almacenando en caché el activo de la aplicación e interceptando las solicitudes a estos y devolviendo las respuestas almacenadas en caché. Esto va más allá del alcance de esta entrada del blog, pero creo que he mostrado lo fácil que es hacer que los datos estén disponibles cuando no se está conectado y mantener todos los clientes del navegador conectados en sincronía, mientras que la aplicación carga los datos rápidamente, y también el cambio de mentalidad de desarrollar Offline-First.
A continuación encontrará GIFs para ver cómo funciona
Puede obtener el código fuente aquí ¡y dale una vuelta!
Buenas tardes. Estoy migrando de SQLite a PounchDB, porque creo que podré sincronizar dos dispositivos sin Internet, pero utilizando la red compartida (HotSpot).
¿Cree que es un buen camino?