Arquitectura

Diseñar tu aplicación para aprovechar al máximo la tecnología que hace que las AWP sean confiables, instalables y capaces comienza por comprender la aplicación y sus limitaciones, y elegir una arquitectura adecuada para ambas.

SPA frente a MPA

En la actualidad, existen dos patrones principales de arquitectura en el desarrollo web: apps de una sola página (SPA) y apps de varias páginas o MPA.

Las apps de una sola página se definen por el hecho de que el código JavaScript del cliente controle la mayor parte o la totalidad del procesamiento HTML de una página en función de los datos recuperados por la app o proporcionados a ella. La app anula la navegación integrada del navegador y la reemplaza con su funcionalidad de enrutamiento y manejo de vistas.

Las apps de varias páginas suelen tener HTML renderizado previamente que se envía directamente al navegador, a menudo mejorado con JavaScript del lado del cliente después de que el navegador termina de cargar el HTML, y dependen de los mecanismos de navegación integrados del navegador para mostrar vistas posteriores.

Ambas arquitecturas se pueden usar para crear AWP.

Cada uno tiene ventajas y desventajas, y seleccionar el más adecuado para tu caso de uso y contexto es clave para brindar una experiencia rápida y confiable a tus usuarios.

Apps de una sola página

Ventajas
  • En su mayoría, son actualizaciones atómicas de los anuncios in-page.
  • Dependencias del cliente cargadas durante el inicio
  • Las cargas posteriores son rápidas debido al uso de caché.
Desventajas
  • Costo de carga inicial alto
  • El rendimiento depende del hardware del dispositivo y de la conexión de red.
  • Se requiere una complejidad adicional de la app.

Las apps de una sola página son una buena opción arquitectónica en los siguientes casos:

  • La interacción del usuario se centra principalmente en actualizaciones atómicas de datos interconectados que se muestran en la misma página, por ejemplo, un panel de datos en tiempo real o una aplicación de edición de video.
  • Tu aplicación tiene dependencias de inicialización solo en el cliente, por ejemplo, un proveedor de autenticación de terceros con un costo de inicio prohibitivamente alto.
  • Los datos necesarios para que una vista se cargue dependen de un contexto específico del lado del cliente, por ejemplo, mostrando controles para un hardware conectado.
  • La app es lo suficientemente pequeña y simple como para que su tamaño y complejidad no influyan en las desventajas mencionadas anteriormente.

Es posible que las SPA no sean una buena opción arquitectónica en los siguientes casos:

  • El rendimiento de la carga inicial es esencial. Las SPA generalmente necesitan cargar más JavaScript para determinar qué cargar y cómo mostrarlo. El tiempo de análisis y ejecución de este JavaScript, combinado con la recuperación de contenido, es más lento que el envío de HTML procesado.
  • La app se ejecuta principalmente en dispositivos que tienen una carga baja a la promedio. Debido a que las SPA dependen de JavaScript para la renderización, la experiencia del usuario depende mucho más de la potencia de su dispositivo específico que en una MPA.

Debido a que las SPA deben reemplazar la navegación integrada del navegador con su enrutamiento, las SPA requieren un nivel mínimo de complejidad en torno a la actualización eficiente de la vista actual, la administración de los cambios de navegación y la limpieza de las vistas anteriores que, de otro modo, controlaría el navegador, lo que hace que, en general, sean más difíciles de mantener y que el dispositivo del usuario se vea más gravado.

Apps de varias páginas

Ventajas
  • La mayoría de las actualizaciones son de página completa.
  • La velocidad de renderización inicial es fundamental.
  • La secuencia de comandos del cliente puede ser una mejora.
Desventajas
  • Las vistas secundarias requieren otra llamada al servidor.
  • El contexto no se traslada entre vistas.
  • Requiere un servidor o procesamiento previo.

Las apps de varias páginas son una buena opción arquitectónica en los siguientes casos:

  • La interacción del usuario se centra principalmente en las vistas de un solo dato con datos opcionales basados en el contexto, por ejemplo, una aplicación de noticias o de comercio electrónico.
  • La velocidad de renderización inicial es fundamental, ya que enviar HTML ya renderizado al navegador es más rápido que ensamblarlo a partir de una solicitud de datos después de cargar, analizar y ejecutar una alternativa basada en JavaScript.
  • La interactividad o el contexto del cliente se puede incluir como una mejora después de la carga inicial, por ejemplo, superponer un perfil en una página renderizada o agregar componentes secundarios que dependen del contexto del cliente.

Las MPA podrían no ser una buena opción arquitectónica en las siguientes situaciones:

  • Volver a descargar, volver a analizar y ejecutar nuevamente tu JavaScript o CSS tiene un costo muy costoso. Esta desventaja se mitiga en las AWP con service worker.
  • El contexto del cliente, como la ubicación del usuario, no se transfiere fácilmente entre vistas, por lo que volver a obtener ese contexto puede ser costoso. Se debe capturar y recuperar, o bien volver a solicitarse entre vistas.

Porque un servidor debe procesar las vistas individuales de forma dinámica o hacerlo antes del acceso, lo que podría limitar el hosting o aumentar la complejidad de los datos.

¿Cuál elegir?

Incluso con estas ventajas y desventajas, ambas arquitecturas son válidas para crear tu AWP. Incluso puedes combinarlos para diferentes partes de tu aplicación, según sus necesidades, por ejemplo, hacer que las fichas de Play Store sigan una arquitectura de MPA y el flujo de confirmación de la compra sigan una arquitectura de SPA.

Independientemente de tu elección, el siguiente paso es comprender cómo usar mejor los service workers para brindar la mejor experiencia.

La potencia de un service worker

El service worker tiene mucha potencia más allá del enrutamiento básico y la entrega de respuestas almacenadas en caché y de red. Podemos crear algoritmos complejos que pueden mejorar la experiencia y el rendimiento del usuario.

Service worker incluye (SWI)

Un patrón emergente para usar service worker como parte integral de la arquitectura de un sitio es el service worker incluye (SWI). SWI divide los elementos individuales (por lo general, una página HTML) en partes según sus necesidades de almacenamiento en caché y, luego, los une en el service worker para mejorar la coherencia, el rendimiento y la confiabilidad, a la vez que reduce el tamaño de la caché. Un sitio web con un encabezado global, un área de contenido, una barra lateral y un pie de página.

Esta imagen es una página web de muestra. Tiene cinco secciones diferentes que dividen la página en:

  • Diseño general
  • Encabezado global (barra oscura superior).
  • Área de contenido (imagen y líneas del medio a la izquierda)
  • Barra lateral (barra alta de tono oscuro intermedio en el medio a la derecha)
  • Pie de página (barra inferior oscura).

Diseño general

Es probable que el diseño general no cambie con frecuencia y no tenga dependencias. Es un buen candidato para el almacenamiento previo en caché.

El encabezado y el pie de página globales contienen elementos como el menú superior y el pie de página del sitio, y presentan un desafío particular: si la página se almacenara en caché como un todo, esto podría cambiar entre las cargas de página, dependiendo de cuándo se almacenó en caché la página dada.

Si los separas y los almacenas en caché independientemente del contenido, puedes garantizar que los usuarios siempre obtendrán la misma versión, sin importar cuándo estén almacenados en caché. Debido a que no se actualizan con frecuencia, también son buenos candidatos para el almacenamiento previo en caché. Sin embargo, tienen una dependencia: el CSS y JavaScript del sitio.

CSS y JavaScript

Idealmente, el CSS y JavaScript del sitio se deberían almacenar en caché con una estrategia inactiva mientras se revalida la estrategia para permitir las actualizaciones incrementales sin necesidad de actualizar el service worker, como es el caso de los recursos prealmacenados en caché. No obstante, también deben mantenerse en una versión mínima cada vez que el service worker se actualiza con un nuevo encabezado o pie de página global. Por esta razón, su caché también debe actualizarse con la última versión de los elementos cuando se instala el service worker.

Área de contenido

Lo siguiente es el área de contenido. Según la frecuencia de las actualizaciones, una buena estrategia es implementar primero la red o dejarla inactiva mientras se vuelve a validar. Las imágenes deben almacenarse en caché con una estrategia que priorice la caché, como se debatió anteriormente.

Por último, suponiendo que el contenido de la barra lateral incluye contenido secundario, como etiquetas y elementos relacionados, no es lo suficientemente crítico como para extraerlo de la red. Una estrategia inactiva mientras se revalida funciona para esto.

Ahora, después de revisar todo eso, es posible que pienses que solo puedes hacer este tipo de almacenamiento en caché por sección para apps de una sola página. Sin embargo, si adoptas patrones inspirados en las inclusiones perimetrales o inclusiones del servidor de tu service worker, con algunas funciones avanzadas de service worker, puedes hacer esto para cualquiera de las arquitecturas.

Pruébalo

Puedes probar las inclusiones del service worker en el siguiente codelab:

Respuestas en tiempo real

La página anterior se podría crear con el modelo de shell de app en el mundo SPA, donde el shell de app se almacena en caché, luego se entrega y el contenido se carga en el lado del cliente. Con la introducción y la amplia disponibilidad de la API de Streams, tanto el shell de la app como el contenido se pueden combinar en el service worker y transmitirse al navegador, lo que te brinda la flexibilidad de almacenamiento en caché del shell de la app con la velocidad de las MPA.

Lo hace por los siguientes motivos:

  • Las transmisiones se pueden compilar de forma asíncrona, lo que permite que diferentes partes de una transmisión provengan de otras fuentes.
  • El solicitante de una transmisión puede comenzar a trabajar en la respuesta no bien esté disponible el primer bloque de datos, en lugar de esperar a que se complete el elemento completo.
  • Los analizadores optimizados para transmisión, incluido el navegador, pueden mostrar progresivamente el contenido de la transmisión antes de que se complete, lo que acelera el rendimiento percibido de la respuesta.

Gracias a estas tres propiedades de las transmisiones, las arquitecturas basadas en transmisiones suelen tener un rendimiento percibido más rápido que las que no lo son.

Trabajar con la API de Streams puede ser desafiante, ya que es compleja y de bajo nivel. Afortunadamente, existe un módulo de Workbox que puede ayudarte a configurar las respuestas de transmisión para los service worker.

Dominios, orígenes y alcance de la AWP

Los trabajadores web, incluidos los service worker, el almacenamiento e incluso la ventana de una AWP instalada, están regidos por uno de los mecanismos de seguridad más importantes de la Web: la política del mismo origen. Dentro del mismo origen, se otorgan permisos, se pueden compartir datos y el service worker puede comunicarse con diferentes clientes. Fuera del mismo origen, los permisos no se otorgan automáticamente y los datos se aíslan y no se puede acceder a ellos entre orígenes diferentes.

Política del mismo origen

Se define que dos URLs tienen el origen exacto si el protocolo, el puerto y el host son iguales.

Por ejemplo: https://squoosh.app y https://squoosh.app/v2 tienen el mismo origen, pero http://squoosh.app, https://squoosh.com, https://app.squoosh.app y https://squoosh.app:8080 tienen orígenes diferentes. Para obtener más información y ejemplos, consulta la referencia de MDN de la política del mismo origen.

Cambiar subdominios no es la única forma en que puede hacerlo un host. Cada host consta de un dominio de nivel superior (TLD), un dominio de nivel secundario (SLD) y cero o más etiquetas (a veces llamadas subdominios), separadas por puntos intermedios y se leen de derecha a izquierda en una URL. Un cambio en cualquiera de los elementos genera un host diferente.

En el módulo de administración de ventanas, ya vimos cómo se ve el navegador de la app cuando un usuario navega a un origen diferente desde una AWP instalada.

Ese navegador en la app aparecerá incluso si los sitios web tienen el mismo TLD y SLD, pero con etiquetas diferentes, ya que luego se consideran orígenes distintos.

Uno de los aspectos clave de un origen en un contexto de navegación web es el funcionamiento del almacenamiento y los permisos. Un origen comparte muchas funciones entre todo el contenido y las AWP que contiene, incluidas las siguientes:

  • Cuota y datos de almacenamiento (IndexedDB, cookies, almacenamiento web, almacenamiento en caché).
  • Registros de service worker
  • Permisos otorgados o denegados (por ejemplo, web push, ubicación geográfica, sensores)
  • Registros push web

Cuando pasas de un origen a otro, se revoca todo el acceso anterior, por lo que se deben volver a otorgar los permisos, y la AWP no podrá acceder a todos los datos guardados en el almacenamiento.

Recursos