Skip to main content

Lo que el equipo de Bulletin aprendi贸 sobre los trabajadores de servicio mientras desarrollaba una PWA.

Esta es la primera de una serie de publicaciones de blog sobre las lecciones que aprendi贸 el equipo de Google Bulletin al crear una PWA externa. En estas publicaciones compartiremos algunos de los desaf铆os que enfrentamos, los enfoques que tomamos para superarlos y consejos generales para evitar trampas. Esta no es de ninguna manera una descripci贸n general completa de las PWA. El objetivo es compartir los aprendizajes de la experiencia de nuestro equipo.

Para esta primera publicaci贸n, primero cubriremos un poco de informaci贸n general y luego profundizaremos en todo lo que aprendimos sobre los trabajadores de servicios.

Bulletin se cerr贸 en 2019 debido a la falta de ajuste de producto / mercado. 隆A煤n aprendimos mucho sobre las PWA a lo largo del camino!

Antecedentes

Bulletin estuvo en desarrollo activo desde mediados de 2017 hasta mediados de 2019.

Por qu茅 elegimos construir una PWA

Antes de profundizar en el proceso de desarrollo, examinemos por qu茅 crear una PWA fue una opci贸n atractiva para este proyecto:

  • Capacidad para iterar r谩pidamente. Especialmente valioso ya que Bulletin se probar铆a en m煤ltiples mercados.
  • Base de c贸digo 煤nico. Nuestros usuarios se dividieron aproximadamente en partes iguales entre Android e iOS. Una PWA significaba que pod铆amos crear una 煤nica aplicaci贸n web que funcionara en ambas plataformas. Esto aument贸 la velocidad y el impacto del equipo.
  • Actualizado r谩pidamente e independientemente del comportamiento del usuario. Las PWA pueden actualizarse autom谩ticamente, lo que reduce la cantidad de clientes desactualizados en la naturaleza. Pudimos impulsar cambios importantes en el backend con un tiempo de migraci贸n muy corto para los clientes.
  • Se integra f谩cilmente con aplicaciones propias y de terceros. Tales integraciones eran un requisito para la aplicaci贸n. Con una PWA, a menudo significaba simplemente abrir una URL.
  • Se elimin贸 la fricci贸n de instalar una aplicaci贸n.

Nuestro marco

Para Bulletin, usamos Pol铆mero, pero cualquier marco moderno y bien soportado funcionar谩.

Lo que aprendimos sobre los trabajadores de servicios

No puedes tener una PWA sin una trabajador del servicio. Los trabajadores de servicios le brindan mucho poder, como estrategias avanzadas de almacenamiento en cach茅, capacidades fuera de l铆nea, sincronizaci贸n en segundo plano, etc. Si bien los trabajadores de servicios agregan algo de complejidad, descubrimos que sus beneficios superan la complejidad adicional.

Generalo si puedes

Evite escribir un script de trabajador de servicio a mano. Escribir trabajadores de servicios a mano requiere administrar manualmente los recursos almacenados en cach茅 y reescribir la l贸gica que es com煤n a la mayor铆a de las bibliotecas de trabajadores de servicios, como Neceser de costura.

Dicho esto, debido a nuestra pila de tecnolog铆a interna, no pudimos usar una biblioteca para generar y administrar nuestro trabajador de servicio. Nuestros aprendizajes a continuaci贸n reflejar谩n en ocasiones eso. Vaya a Problemas para los trabajadores de servicios no generados para leer m谩s.

No todas las bibliotecas son compatibles con los trabajadores de servicios

Algunas bibliotecas de JS hacen suposiciones que no funcionan como se esperaba cuando las ejecuta un trabajador del servicio. Por ejemplo, asumiendo window o document est谩n disponibles, o usando una API no disponible para los trabajadores del servicio (XMLHttpRequest, almacenamiento local, etc.). Aseg煤rese de que las bibliotecas cr铆ticas que necesite para su aplicaci贸n sean compatibles con los trabajadores de servicios. Para esta PWA en particular, quer铆amos usar
gapi.js para la autenticaci贸n, pero no pudieron hacerlo porque no admit铆a a los trabajadores del servicio. Los autores de bibliotecas tambi茅n deben reducir o eliminar suposiciones innecesarias sobre el contexto de JavaScript siempre que sea posible para respaldar los casos de uso de trabajadores de servicios, como evitar API incompatibles con trabajadores de servicios y evitar el estado global.

Evite acceder a IndexedDB durante la inicializaci贸n

No leas IndexedDB al inicializar su script de trabajador de servicio, o puede entrar en esta situaci贸n no deseada:

  1. El usuario tiene una aplicaci贸n web con IndexedDB (IDB) versi贸n N
  2. Se incluye una nueva aplicaci贸n web con la versi贸n N + 1 del BID
  3. El usuario visita PWA, que activa la descarga de un nuevo trabajador de servicio
  4. El nuevo trabajador de servicios lee del BID antes de registrarse install manejador de eventos, activando un ciclo de actualizaci贸n del BID para pasar de N a N + 1
  5. Dado que el usuario tiene un cliente antiguo con la versi贸n N, el proceso de actualizaci贸n del trabajador del servicio se bloquea ya que las conexiones activas todav铆a est谩n abiertas a la versi贸n anterior de la base de datos
  6. El trabajador de servicio se cuelga y nunca instala

En nuestro caso, el cach茅 se invalida en la instalaci贸n del trabajador del servicio, por lo que si el trabajador del servicio nunca se instal贸, los usuarios nunca recibieron la aplicaci贸n actualizada.

Hazlo resistente

Aunque los scripts de los trabajadores de servicios se ejecutan en segundo plano, tambi茅n se pueden finalizar en cualquier momento, incluso cuando se encuentran en medio de operaciones de E / S (red, IDB, etc.). Cualquier proceso de larga duraci贸n deber铆a poder reanudarse en cualquier momento.

En el caso de un proceso de sincronizaci贸n que carg贸 archivos grandes al servidor y se guard贸 en el BID, nuestra soluci贸n para las cargas parciales interrumpidas fue aprovechar el sistema reanudable de nuestra biblioteca de carga interna, guardando la URL de carga reanudable en el BID antes de cargar y usar esa URL para reanudar una carga si no se complet贸 la primera vez. Adem谩s, antes de cualquier operaci贸n de E / S de larga duraci贸n, el estado se guardaba en IDB para indicar en qu茅 parte del proceso est谩bamos para cada registro.

No dependas del estado global

Debido a que los trabajadores del servicio existen en un contexto diferente, muchos s铆mbolos que podr铆a esperar que existan no est谩n presentes. Gran parte de nuestro c贸digo se ejecut贸 tanto en window contexto, as铆 como un contexto de trabajador de servicio (como registro, banderas, sincronizaci贸n, etc.). El c贸digo debe estar a la defensiva con respecto a los servicios que utiliza, como el almacenamiento local o las cookies. Puedes usar
globalThis

para referirse al objeto global de una manera que funcione en todos los contextos. Tambi茅n use los datos almacenados en variables globales con moderaci贸n, ya que no hay garant铆a de cu谩ndo se terminar谩 el script y se desalojar谩 el estado.

Desarrollo local

Un componente importante de los trabajadores de servicios es el almacenamiento en cach茅 de los recursos localmente. Sin embargo, durante el desarrollo este es el opuesto de lo que desea, especialmente cuando las actualizaciones se realizan con pereza. A煤n desea instalar el trabajador del servidor para poder depurar problemas con 茅l o trabajar con otras API, como sincronizaci贸n en segundo plano o notificaciones. En Chrome, puede lograr esto a trav茅s de Chrome DevTools habilitando el Bypass para red casilla de verificaci贸nSolicitud panel> Trabajadores de servicios panel) adem谩s de habilitar el Desactivar el cach茅 casilla de verificaci贸n en el Red panel para deshabilitar tambi茅n la memoria cach茅. Para cubrir m谩s navegadores, optamos por una soluci贸n diferente al incluir una marca para deshabilitar el almacenamiento en cach茅 en nuestro trabajador de servicio, que est谩 habilitado de forma predeterminada en las compilaciones de desarrolladores. Esto asegura que los desarrolladores siempre obtengan sus cambios m谩s recientes sin problemas de almacenamiento en cach茅. Es importante incluir el Cache-Control: no-cache encabezado tambi茅n para evitar que el navegador almacene en cach茅 cualquier activo.

Faro

Faro proporciona una serie de herramientas de depuraci贸n 煤tiles para las PWA. Escanea un sitio y genera informes que cubren PWA, rendimiento, accesibilidad, SEO y otras mejores pr谩cticas.
Nosotros recomendamos ejecutando Lighthouse en integraci贸n continua para avisarle si no cumple con alguno de los criterios para ser PWA. En realidad, esto nos sucedi贸 una vez, donde el trabajador del servicio no estaba instalando y no nos dimos cuenta antes de un impulso de producci贸n. Tener Lighthouse como parte de nuestro CI lo habr铆a evitado.

Adopte la entrega continua

Debido a que los trabajadores del servicio pueden actualizar autom谩ticamente, los usuarios carecen de la capacidad de limitar las actualizaciones. Esto reduce significativamente la cantidad de clientes desactualizados en la naturaleza. Cuando el usuario abr铆a nuestra aplicaci贸n, el trabajador del servicio serv铆a al cliente anterior mientras descargaba el nuevo cliente con pereza. Una vez que el nuevo cliente se descarg贸, le pedir谩 al usuario que actualice la p谩gina para acceder a nuevas funciones. Incluso si el usuario ignoraba esta solicitud, la pr贸xima vez que actualizara la p谩gina, recibir铆a la nueva versi贸n del cliente. Como resultado, es bastante dif铆cil para un usuario rechazar las actualizaciones de la misma manera que puede hacerlo para las aplicaciones nativas.

Pudimos impulsar cambios importantes en el backend con un tiempo de migraci贸n muy corto para los clientes. Por lo general, damos un mes para que los usuarios se actualicen a clientes m谩s nuevos antes de realizar cambios importantes. Dado que la aplicaci贸n funcionar铆a mientras estaba obsoleta, era posible que los clientes m谩s antiguos existieran en la naturaleza si el usuario no hab铆a abierto la aplicaci贸n durante mucho tiempo. En iOS, los trabajadores del servicio son
desalojado despu茅s de un par de semanas
por lo que este caso no sucede. Para Android, este problema podr铆a mitigarse si no se publica mientras est谩 obsoleto o si el contenido caduca manualmente despu茅s de algunas semanas. En la pr谩ctica, nunca encontramos problemas con clientes obsoletos. Cu谩n estricto quiere ser un equipo dado aqu铆 depende de su caso de uso espec铆fico, pero las PWA brindan una flexibilidad significativamente mayor que las aplicaciones nativas.

Obtener valores de cookies en un trabajador de servicios

A veces es necesario acceder a los valores de las cookies en el contexto de un trabajador de servicios. En nuestro caso, necesit谩bamos acceder a los valores de las cookies para generar un token para autenticar las solicitudes de API de origen. En un trabajador de servicios, las API s铆ncronas como document.cookies no est谩n disponibles. Siempre puede enviar un mensaje a los clientes activos (con ventana) desde el trabajador del servicio para solicitar los valores de las cookies, aunque es posible que el trabajador del servicio se ejecute en segundo plano sin ning煤n cliente con ventana disponible, como durante una sincronizaci贸n en segundo plano. Para solucionar esto, creamos un punto final en nuestro servidor frontend que simplemente devolv铆a el valor de la cookie al cliente. El trabajador del servicio realiz贸 una solicitud de red a este punto final y ley贸 la respuesta para obtener los valores de las cookies.

Con el lanzamiento de la
API de la tienda de cookies, esta soluci贸n alternativa ya no deber铆a ser necesaria para los navegadores que la admiten, ya que proporciona acceso asincr贸nico a las cookies del navegador y puede ser utilizada directamente por el trabajador del servicio.

Escollos para los trabajadores de servicios no generados

Aseg煤rese de que la secuencia de comandos del trabajador del servicio cambie si cambia alg煤n archivo en cach茅 est谩tico

Un patr贸n de PWA com煤n es que un trabajador del servicio instale todos los archivos de aplicaciones est谩ticas durante su
install fase, que permite a los clientes acceder directamente a la cach茅 de la API de almacenamiento en cach茅 para todas las visitas posteriores. Los trabajadores del servicio solo se instalan cuando el navegador detecta que la secuencia de comandos del trabajador del servicio ha cambiado de alguna manera, por lo que ten铆amos que asegurarnos de que el archivo de la secuencia de comandos del trabajador del servicio cambiara de alguna manera cuando cambiaba un archivo en cach茅. Hicimos esto manualmente al incrustar un hash del conjunto de archivos de recursos est谩ticos dentro de nuestro script de trabajador de servicio, por lo que cada versi贸n produjo un archivo JavaScript de trabajador de servicio distinto. Bibliotecas de trabajadores de servicios como
Neceser de costura Automatice este proceso por usted.

Examen de la unidad

Las API de trabajador de servicio funcionan agregando detectores de eventos al objeto global. Por ejemplo:

self.addEventListener('fetch', (evt) => evt.respondWith(fetch('/foo')));

Esto puede ser dif铆cil de probar porque necesita simular el disparador del evento, el objeto del evento, esperar el respondWith() devoluci贸n de llamada, y luego esperar la promesa, antes de finalmente afirmar el resultado. Una forma m谩s sencilla de estructurar esto es delegar toda la implementaci贸n a otro archivo, que se prueba m谩s f谩cilmente.

import fetchHandler from './fetch_handler.js';
self.addEventListener('fetch', (evt) => evt.respondWith(fetchHandler(evt)));

Debido a las dificultades de la prueba unitaria de un script de trabajador de servicio, mantuvimos el script de trabajador de servicio central lo m谩s b谩sico posible, dividiendo la mayor parte de la implementaci贸n en otros m贸dulos. Dado que esos archivos eran solo m贸dulos JS est谩ndar, podr铆an probarse unitariamente m谩s f谩cilmente con bibliotecas de prueba est谩ndar.

Est茅n atentos para las partes 2 y 3

En las partes 2 y 3 de esta serie hablaremos sobre la gesti贸n de medios y problemas espec铆ficos de iOS. Si desea preguntarnos m谩s sobre la creaci贸n de una PWA en Google, visite nuestros perfiles de autor para averiguar c贸mo contactarnos: