Haciendo una aplicación web de Dart offline-capable: 3 líneas de código

¿Alguna vez intentaste cargar una aplicación web (quizás un juego o un convertidor de medidas) y no pudiste usarla porque la red estaba caída…

¿Alguna vez has intentado cargar una aplicación web (quizás un juego o un conversor de medidas) y no has podido usarla porque la red estaba caída? Es una experiencia terrible, pero por suerte tenemos la tecnología para hacer que este tipo de aplicaciones estén disponibles para nuestros usuarios.

Para la mayoría de las aplicaciones y juegos, esto se puede hacer con 3 líneas de código Dart y 1 comando en la terminal. En este breve artículo te guiaré por los pasos, y me aseguraré de que siempre puedas jugar Pop, Pop, Win!

Tablero de juego de Pop, Pop, Win! con casillas numeradas, globos, cinco bombas restantes y un temporizador de 24,5 segundos.
Pop, Pop, Win! — una implementación de Buscaminas en Dart

Service workers

#

Un service worker es un archivo JavaScript que se ejecuta en segundo plano. Puede controlar la página web o el sitio con el que está asociado, interceptando y modificando las peticiones de navegación y recursos, y almacenando recursos en caché de una manera muy granular.

Es una tecnología web no intrusiva: los service workers pueden mejorar la experiencia del usuario si el navegador los soporta, pero el sitio puede funcionar perfectamente en su ausencia (con el comportamiento web por defecto). Esta es una propiedad útil que habilita las aplicaciones web progresivas (PWA), donde puedes proporcionar funcionalidades más avanzadas a la mayoría de los usuarios, asegurándote de que el resto no quede excluido.

Como hilo de procesamiento en segundo plano, un service worker puede ayudar con:

  • modo sin conexión (obteniendo recursos de la caché mientras la red está caída)

  • estrategias de caché (para respuestas casi instantáneas desde la caché que pueden actualizarse más tarde con contenido fresco)

  • notificaciones push (como en una aplicación móvil)

  • mensajería (si la aplicación está abierta en múltiples pestañas)

La funcionalidad importante para nuestra experiencia de juego sin conexión es esta: nos gustaría jugar Pop, Pop, Win!, y no encontrarnos con este dinosaurio:

El juego del dinosaurio sin conexión de Chrome indicando que no hay conexión a internet.
Dato curioso: puedes jugar con ese dinosaurio pulsando la tecla de flecha hacia arriba.

Aplicación web progresiva con Dart

#

Soportar el modo sin conexión requiere aproximadamente lo siguiente:

  1. Determinar qué recursos poner en la caché para uso sin conexión.

  2. Crear un service worker que prepare una caché de estos recursos.

  3. Registrar el service worker, para que las peticiones posteriores puedan ser servidas desde la caché sin conexión (en caso de que la red esté caída).

  4. En ese service worker, poblar previamente la caché sin conexión con las URLs, y también manejar la petición de fetch apropiada ya sea desde la caché o desde la red.

  5. Asegurarse de que el service worker detecte cambios en la aplicación o en los recursos estáticos, y ponga la nueva versión en la caché.

Aunque la lista anterior puede sonar un poco intimidante, tenemos un paquete pwa en Dart que hace la mayor parte del trabajo por nosotros, proporcionando una API de alto nivel y automatizando la mayor parte del trabajo.

Cambios en tu aplicación

#

Importa el paquete pwa en tu pubspec.yaml:

dependencies:
  pwa: ^0.1.2

Después de ejecutar pub get, añade el cliente a tu web/main.dart:

import ‘package:pwa/client.dart’ as pwa;

main() {
  // register PWA ServiceWorker for offline caching.
  new pwa.Client();

}

El código anterior maneja el ítem 3 de la lista anterior registrando el service worker (que crearemos en el siguiente paso). Ahora mismo no usamos la instancia de Client para nada más, pero a medida que el paquete pwa obtenga nuevas funcionalidades, podría ser útil para otros propósitos.

Aplicación web progresiva generada automáticamente

#

El paquete pwa proporciona generación de código que maneja los ítems 1–2 y 4–5 de la lista anterior. Para asegurar un uso adecuado de la caché (tanto para poblar como para invalidar la caché) usa el siguiente flujo de trabajo:

  1. Compila tu aplicación web con todos los recursos estáticos terminando en build/web: pub build

  2. Ejecuta el generador de código de pwa para escanear (o reescanear) tus recursos sin conexión: pub run pwa

  3. Compila tu proyecto de nuevo, porque necesitas tener tu archivo (nuevo) pwa.dart compilado: pub build

Estos pasos producen un archivo llamado lib/pwa/offline_urls.g.dart que contiene una lista de las URLs sin conexión para almacenar en caché. La extensión .g.dart indica que el archivo es generado y puede ser sobrescrito automáticamente por la herramienta generadora de código de pwa.

En la primera ejecución, este flujo de trabajo genera el archivo web/pwa.dart que contiene tu service worker con valores predeterminados razonables. Puedes modificar este archivo (para personalizar las URLs sin conexión o usar las APIs de alto nivel, por ejemplo) porque el generador de código no lo cambiará ni lo sobrescribirá de nuevo.

Advertencias

#

Aunque Dartium es excelente para la mayoría del desarrollo web, en este momento es difícil de usar con service workers. Recomendamos usar Chrome o Firefox en su lugar.

La invalidación de la caché es uno de los problemas más difíciles en la informática. La Web Cache API subyacente proporciona algunas garantías, y la librería pwa se esfuerza mucho para manejar elegantemente los casos extremos, pero no trates la caché como almacenamiento confiable para nada realmente importante. Usa la caché cuando esté disponible, y falla de forma elegante cuando no lo esté.

Pruébalo

#

Ahora puedes desplegar la nueva versión de tu aplicación. O probar el juego Pop, Pop, Win! sin conexión.

Después de abrir el juego y jugar una ronda, apaga tu wi-fi o desconecta el cable de red, y luego recarga (o vuelve a escribir la URL). Si estás usando Chrome o Firefox, tu juego debería estar funcionando. ¡Buena suerte, que te diviertas!

Más de Dart