Arquitectura

El diseño de tu aplicación para aprovechar al máximo la tecnología que hace que las AWP sean confiables, instalables y capaces comienza con la comprensión de tu aplicación y sus restricciones, y la elección de una arquitectura adecuada para ambas.

SPA en comparación con MPA

En la actualidad, existen dos patrones arquitectónicos principales en el desarrollo web: las apps de una sola página, o SPA, y las aplicaciones de varias páginas, o MPA.

Las apps de una sola página se definen porque tienen un control de JavaScript del cliente sobre la mayor parte o la totalidad de la renderización HTML de una página según los datos que recupera o proporciona la app. La app anula la navegación integrada del navegador y la reemplaza con su funcionalidad de enrutamiento y control de vistas.

Por lo general, las apps de varias páginas tienen HTML renderizado previamente que se envía directamente al navegador, a menudo mejorado con JavaScript del cliente después de que el navegador termina de cargar el HTML y se basa en 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 adecuado para tu caso de uso y contexto es clave para proporcionar una experiencia rápida y confiable a tus usuarios.

Apps de una sola página

Ventajas
  • Mayormente actualizaciones in-page atómicas.
  • Dependencias del cliente cargadas en el inicio
  • Las cargas posteriores son rápidas debido al uso de la caché.
Desventajas
  • Alto costo de carga inicial.
  • El rendimiento depende del hardware del dispositivo y de la conexión de red.
  • Se requiere 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 las 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 app de edición de video.
  • Tu aplicación tiene dependencias de inicialización solo del cliente, por ejemplo, un proveedor de autenticación de terceros con un costo de inicio prohibitivo.
  • Los datos necesarios para que se cargue una vista dependen de un contexto específico solo del cliente, por ejemplo, mostrar controles para un hardware conectado.
  • La app es lo suficientemente pequeña y simple como para que su tamaño y complejidad no tengan un impacto en las desventajas mencionadas anteriormente.

Es posible que los SPA no sean una buena opción de arquitectura en los siguientes casos:

  • El rendimiento de la carga inicial es esencial. Por lo general, las SPA necesitan cargar más JavaScript para determinar qué cargar y cómo mostrarlo. El tiempo de análisis y ejecución de este código JavaScript, combinado con la recuperación de contenido, es más lento que enviar HTML renderizado.
  • Tu app se ejecuta principalmente en dispositivos de baja a potencia 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 SPAs deben reemplazar la navegación integrada del navegador con su enrutamiento, requieren un nivel mínimo de complejidad para actualizar de manera eficiente la vista actual, administrar los cambios de navegación y limpiar las vistas anteriores que, de otro modo, el navegador manejaría, lo que las hace más difíciles de mantener y más exigentes para el dispositivo del usuario.

Apps de varias páginas

Ventajas
  • Mayormente, actualizaciones de página completa.
  • La velocidad de renderización inicial es fundamental.
  • Las secuencias de comandos del cliente pueden ser una mejora.
Desventajas
  • Las vistas secundarias requieren otra llamada al servidor.
  • El contexto no se transfiere entre vistas.
  • Requiere un servidor o procesamiento previo.

Las apps de varias páginas son una buena opción de arquitectura 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 app de noticias o de comercio electrónico.
  • La velocidad de renderización inicial es fundamental, ya que enviar HTML 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 pueden 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 de arquitectura en los siguientes casos:

  • Volver a descargar, analizar y ejecutar tu código JavaScript o CSS es prohibitivamente costoso. Esta desventaja se mitiga en las AWP con service workers.
  • El contexto del cliente, como la ubicación del usuario, no se traslada sin problemas entre vistas, y volver a obtener ese contexto puede ser costoso. Se debe capturar y recuperar, o volver a solicitar entre vistas.

Porque las vistas individuales deben procesarse de forma dinámica con un servidor o deben renderizarse previamente 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 app, según sus necesidades, por ejemplo, hacer que las fichas de Play Store sigan una arquitectura de MPA y que el flujo de confirmación de la compra sigan una arquitectura SPA.

Independientemente de la opción que elijas, el siguiente paso es comprender cómo usar mejor los trabajadores del servicio para brindar la mejor experiencia.

El poder de service worker

El trabajador de servicio 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 includes (SWI)

Un patrón emergente para usar los trabajadores del servicio como parte integral de la arquitectura de un sitio es la inclusión de trabajadores del servicio (SWI). El SWI divide los recursos individuales, por lo general, una página HTML, en partes según sus necesidades de almacenamiento en caché y, luego, los vuelve a unir en el trabajador de servicio 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 lo siguiente:

  • Diseño general.
  • Encabezado global (barra oscura superior).
  • Área de contenido (líneas centrales izquierdas y la imagen)
  • Barra lateral (barra alta de color medio oscuro en el medio derecho).
  • 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 una buena opción 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é en su totalidad, estos podrían cambiar entre cargas de página, según el momento en que se almacenó en caché la página determinada.

Si los separas y almacenas en caché independientemente del contenido, puedes asegurarte de que los usuarios siempre obtengan la misma versión, independientemente de cuándo se almacenen en caché. Como se actualizan con poca frecuencia, también son buenos candidatos para el almacenamiento previo en caché. Sin embargo, tienen una dependencia: el CSS y el JavaScript del sitio.

CSS y JavaScript

Idealmente, el CSS y el JavaScript del sitio deben almacenarse en caché con una estrategia de inactividad mientras se vuelve a validar para permitir actualizaciones incrementales sin necesidad de actualizar el trabajador del servicio, como es el caso de los recursos almacenados en caché previamente. Sin embargo, también deben mantenerse en una versión mínima cada vez que el trabajador de servicio se actualiza con un nuevo encabezado o pie de página global. Por este motivo, su caché también debe actualizarse con la versión más reciente de los recursos cuando se instale el servicio trabajador.

Área de contenido

A continuación, se muestra el área de contenido. Según la frecuencia de las actualizaciones, una buena estrategia es usar primero la red o usar datos inactivos mientras se vuelve a validar. Las imágenes deben almacenarse en caché con una estrategia de almacenamiento en caché en primer lugar, como se mencionó anteriormente.

Por último, si suponemos que el contenido de la barra lateral contiene contenido secundario, como etiquetas y elementos relacionados, no es lo suficientemente importante como para extraerlo de la red. Para esto, funciona una estrategia de inactividad mientras se vuelve a validar.

Ahora, después de revisar todo esto, 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 los incluidos del borde o los incluidos del servidor en tu service worker, con algunas funciones avanzadas de este, puedes hacerlo para cualquiera de las arquitecturas.

Pruébalo

Puedes probar el servicio trabajador incluido en el siguiente codelab:

Respuestas de transmisión

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

Esto se debe a lo siguiente:

  • 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 en cuanto esté disponible el primer fragmento de datos, en lugar de esperar a que se complete todo el elemento.
  • Los analizadores optimizados para la transmisión, incluido el navegador, pueden mostrar de forma progresiva 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 creadas en torno a la transmisión suelen tener un rendimiento percibido más rápido que las que no lo son.

Trabajar con la API de Streams puede ser un desafío, ya que es compleja y de bajo nivel. Afortunadamente, existe un módulo de la caja de trabajo que puede ayudar a configurar las respuestas de transmisión para los service workers.

Dominios, orígenes y alcance de la AWP

Los trabajadores web, incluidos los service workers, el almacenamiento y hasta la ventana de una AWP instalada, se rigen 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 trabajador del servicio puede comunicarse con diferentes clientes. Fuera del mismo origen, los permisos no se otorgan automáticamente, los datos están aislados y no se puede acceder a ellos entre diferentes orígenes.

Política de mismo origen

Dos URLs se definen como teniendo el origen exacto si el protocolo, el puerto y el host son los mismos.

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 están en orígenes diferentes. Consulta la referencia de MDN de la política del mismo origen para obtener más información y ejemplos.

Cambiar los subdominios no es la única forma en que un host puede cambiar. Cada host se compone 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 dará como resultado un host diferente.

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

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

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 incluye, incluidas las siguientes:

  • Datos y cuota de almacenamiento (IndexedDB, cookies, almacenamiento web y almacenamiento en caché)
  • Registros de service workers
  • Permisos otorgados o denegados (como notificaciones web push, ubicación geográfica y sensores)
  • Registros de notificaciones 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 tu AWP no puede acceder a todos los datos guardados en el almacenamiento.

Recursos