Crear una PWA con Create React App: Lecciones aprendidas

Lecciones aprendidas durante el desarrollo de una PWA utlizando Create React App: Budget Tracker

Empezé trabajando con React hace unos años, siempre he comenzado los proyectos desde cero, sin utilizar ninguna plantilla o generador de proyectos. En lo que ser refiere a los empaquetadores, normalmente utilizo Webpack en el trabajo o Parcel en proyectos personales.

Hace unos meses, quería comenzar un proyecto personal para hacer un seguimiento de mis gastos durante mi año sabático, Budget Tracker lo llamé. Llevaba un poco de prisa, porque en ese momento llevaba ya unos 4 meses viajando y quería centrarme cuanto antes en implementar la funcionalidad principal y tener algo funcionando cuanto antes, un MVP (minimum viable product), estaba en la situación perfecta para probar Create React App o CRA.

Note
CRA te permite crear una PWA en React lista para producción en un momento, lo que es impresionante. Solo tienes el esqueleto de la aplicación, tampoco hace milagros, el resto lo tienes que programar tú. CRA se encarga de la gestión de dependencias de desarrollo y configuración de el empaquetador, Webpack en este caso.

Como decía antes, quería implementar la lógica del programa cuanto antes, así que junto con la utilización de CRA, tambien tomé otras decisiones y atajos, condicionados por la necesidad de acelerar el proceso de desarrollo, hablaré sobre todas estas decisiones a lo largo de este artículo.

Tecnologías escogidas para crear Budget Tracker

Estoy bastante contento con el resultado, pero teniendo en cuenta lo aprendido durante el desarrollo de este proyecto, en el futuro y con el tiempo suficiente, lo más seguro es que no volviese a elegir este mismo conjunto.

Puedes evaluar el resultado de usar este conjunto de tecnologías abriendo Budget Tracker.

A continuación, haré un análisis más detallado de algunos de los beneficios e inconvenientes de las decisiones y atajos que tomé durante el desarrollo de Budget Tracker.

Create React Application: CRA

Create React App no ofrece soporte para Web Workers ni permite modificar la implementación del Service Worker sin expulsar (eject) la configuración.

Note
¿Qué significa explusar o “eject” en CRA? Básicamente es que la configuración de tu proyecto ya no está gestionada por CRA, por lo que tienes que te tienes que hacer cargo de ella, mantener las dependencias y configuración de todos los aspectos de tu proyecto como las pruebas, el análisis estático de código, la configuración de Babel y la lista continúa.

Service worker

Es posible que necesites modificar el comportamiento de tu Service Worker para enviar/recibir mensajes post, para realizar sincronización en segundo plano o mostrar notificaciones web. En ese caso tendrá que extraer tu proyecto (eject) y mantener la configuración por tí misma/mismo, lo cual puede suponer algún que otro dolor de cabeza innecesario.

Hay otras opciones para evitar extraer CRA, pero son un poco complicadas para mi gusto.

Web worker

Cuando necesitas ejecutar algún procesamiento sin bloquear el hilo principal, puedes enviarlo a un Web Workers, lo malo es que tampoco están soportados por CRA. El Web Workers también puebe comunicarse con el hilo principal usando mensajes post y también puede mostrar notificaciones web.

También hay otras opciones para evitar extraer la configuración de CRA, pero requieren un poco de trabajo extra.

Webpack

Webpack es el empaquetador utilizado por CRA. Cuando utilizas CRA, no necesitas saber mucho sobre éste, pero cuando tienes que extraer tu proyecto (eject), entonces tendrás que lidiar con el archivo de configuracion de Webpack.

Firebase

Budget Tracker permite sincronizar tus presupuestos entre distintos dispositivos, por lo que esta aplicación necesita un lado backend para gestionar la autenticación y guardar/leer los datos. Consideré dos opciones: Firebase implementar una API REST.

Elegí Firebase porque no hay que implementar nada en el lado servidor, sólo hay que configurar los métodos de autenticación y las reglas de seguridad en Firestore.

Pero Firebase viene con algunos inconvenientes que debes conocer antes de elegirlo.

Inconvenientes

Tamaño de la librería

Me sorprendió mucho la primera vez que analicé el tamaño de la aplicación Budget Tracker justo después de integrarla con Firebase, ¡creció un 39%!.

Afortunadamente Budget Tracker está implementado particionando el código (code-splitting), lo que permite cargar solo las partes necesarias de la aplicación, así que, la experiencia de usuario no se vió gravemente afectada. Lo malo es que el usuario, en algún momento, tendrá que descargar ese 39% extra (539KB).

No realmente primero offline

Important
Esto no es relevante, si para tu caso de uso no tienes que vincular los datos al usuario.

Firestore necesita un usuario identificado para realizar lecturas y escrituras, pero permite trabajar con usuarios anónimos, esta característica es muy interesante si no quieres forzar al usuario a identificarse para utilizar la aplicación.

Otra característica muy útil es que soporta modo offline, lo que permite guardar y leer información cuando no hay conexión a Internet.

Los usuarios anónimos junto con el modo offline, casi permiten tener una aplicación que funcione completamente offline.

Entonces… ¿Qué es esto de No realmente primero offline? Esto significa, que la primera vez que la aplicación es abierta, Firebase necesita identificar al usuario, para ello, en este momento, el dispositivo del usuario debe estar conectado a Internet, en este caso, debes considerar el siguiente escenario:

  1. La PWA está instalada en tu dispositivo.

  2. El usuario no está identificado.

  3. El dipositivo no tiene acceso a Internet.

  4. El usuario abre la PWA e intenta guardar o leer datos.

  5. La información no se podrá guardar correctamente, porque se desconoce el usuario al que pertenece esta información y tampoco se puede vincular a un usuario anónimo, porque se necesita conexión para crearlo.

Esto no es un problema importane, la aplicación funcionará perfectamente en la mayoría de casos. Si, aún así quieres resolver este caso, a continuación explicaré cómo lo he solucionado en Budget Tracker.

Convertir Budget Tracker como offline first

Antes de nada, me gustaría remarcar que esto podría no ser necesario para tu caso de uso, porque sólo ocurrirá la primera vez que arranque la aplicación y no tenga conexión a Internet. En el caso de Budget Tracker me aseguré de que funcionase en todo momento en modo offline porque traía otros beneficios que más adelante enumeraré.

Detalles de implementación
  • Crear dos capas de persistencia: Local (IndexedDB) y Remota (Firestore).

  • Guardar los datos siempre de forma local, independientemente de si el usuario está identificado o no.

  • Si hay un usuario que ya está identificado, después de actuar sobre el almacenamiento local, realizar exactamente la misma acción sobre la capa de almacenamiento remoto Firestore de forma asíncrona.

Beneficios
  • Si el usuario no se ha identificado, Budget Tracker no cargará la librería cliente de Firestore. Como ya comenté antes, ésta supone un 27% del tamaño de la aplicación.

  • Las escrituras y lecturas son algo más rápidas, porque el almacenamiento primario es local.

  • Aclaración: La interación con Firestore también es rápida, porque también almacena la información localmente, pero también hace unas cuantas cosas más que simplemente interactuar con IndexedDB y necesitas un usuario identificado.

Puedes encontrar un informe más detallado sobre el rendimiento, donde se analizan tres escenarios diferentes:

  1. Firestore como única capa de persistencia.

  2. Dos capas de persistencia, una local (IndexedDB) y otra remota (Firestore),

  3. Igual que la anterior, pero se interactúa con Firestore desde un service worker.

En general, se obtienen mejores resultados con la opción 2.

Modelo de Datos

La API de Firestore es fácil e intuitiva, me encanta, pero no asumas que tendrá todas las características que ofrecen otras bases de datos documentales o relacionales (SQL).

Comprueba que las limitaciones de Firestore encajan con tu modelo de datos, o si no es demasiado tarde, diseña tu modelo de datos siguiendo la guía de buenas prácticas de Firestore.

Alternativas a Firebase

A parte de implementar una API REST para tu aplicación, hay otros servicios similares a Firebase con un tamaño menor de la librería cliente y otras características que pueden adaptarse mejor a tus necesidades.

Algunas alternativas a considerar:

Librería de componentes de interfaz de usuario: Material UI

Elegí Material UI.

Componentes de React para un desarrollo web más rápido y sencillo. Construya su propio sistema de diseño, o empiece con Material Design.
— https://material-ui.com[Material UI

Hay dos razones principales por las que elegí una libreria de componentes UI:

  • Es laborioso crear tus propios componentes de interfaz de usuario que sean accesibles, que se adapten correctamente a distintos dispositivos y con un diseño estéticamente correcto.

  • Material UI tiene un conjunto de iconos SVG, Material Icons. Esto me venía muy bien para Budget Tracker, porque permite crear categorías para gastos y asignar un icono a éstas categorías.

Hay algunos problemas, no muy importantes en mi opinión, quizá el que me resulta más molesto es el primero:

Librerías de gráficas

Muchas de las librerías que he encontrado son muy potentes y completas, pero también ocupan bastante, entre otras cosas porque dependen en otras librerías como D3.

Inicialmente elegí Victory, pero me dí cuenta de que sólamente necesitaba gráficos para mostrar porcentajes y series temporales. Otro hecho relevante es que Victory tiene un tamaño de 468KB y yo no estaba utilizando la mayor parte de ese código.

Después de una búsqueda rápida en Internet, encontré otras alternativas mucho más ligeras y más que suficientes para mis necesidades:

Probé las dos y me encantaron las dos, finalmente elegí Frappe charts porque su esquema de colores se ajusta mejor al tema de Budget Tracker.

Ambas librerías traen más tipos de gráficos que los de ejes de coordenadas XY o gráfico de barras. Echa un vistazo a sus sitios web si quieres saber un poco más.

Conclusión

Intentaré llegar a una conclusión algo mejor que "Depende", "Tu caso de uso te dirá", etc. Dicho esto, depende de lo que necesites :p.

Ya en serio, voy a listar las conclusiones en la forma "No utilices … si …".

No utilices CRA si

No utilices Firestore si

  • Si esperas que tu aplicación sea utilizada por muchos usuarios y no tienes idea de la cantidad de lecturas y escrituras que necesitas por usuario, te podrías llevar un sorpresa en la factura que te pase Google. Firestore escala perfectamente, pero tu presupuesto quizá no.

  • Si el tamaño de tu aplicación web es algo crítico. Recuerda que el tamaño de tu aplicación, si se trata de una PWA, no es tan importante, porque los archivos normalmente estará cacheados para que la aplicación pueda abrirse offline.

No elijas la mejor librería de gráficos

Antes de nada, analiza qué tipos de gráficos necesitas. En muchos casos, es más que suficiente con gráficos XY, de tarta o de barras. Puedes fácilmente reducir el tamaño de tu aplicación utilizando librerías como Frappe charts or Chartist

Tip
Simplemente asegúrate de que tus requisitos son compatibles con las limitaciones o problemas de los que acabo de hablar. Si no estás segura o seguro, las Tecnologías escogidas para crear Budget Tracker debería ser suficiente para cualquier PWA.

¿Y ahora qué?

Mi próxima apuesta para el lado frontend es {Svelte}/{Sapper}. Es un proyecto prometedor que ha cambiado el paradigma de framework en tiempo de ejecución a framework en tiempo de compilación. Hasta ahora, los resultados en proyectos pequeños son impresionantes, sobre todo en lo relacionado con el tamaño de la aplicación generada y con lo fácil e intuitivo que resulta el desarrollo con {Svelte}.

He creado una sencilla PWA para calcular el dinero que pierdes cuando vas a una casa de cambio: currency-loss.netlify.com.

Terminé esta aplicación en pocas horas gracias a {Svelte}.