PWAs: El Manifiesto, el modelo App Shell y PRPL

Sebastian Vega

Sebastian Vega

Compartir

PWAs: El Manifiesto, el modelo App Shell y PRPL

En la historia anterior, vimos los conceptos básicos de una PWA. En este artículo iba a profundizar en el manifiesto de nuestra aplicación, pero ya hice una introducción anteriormente que creo que es suficiente, además esto está mas que bien documentado y ejemplificado en google developers y mozilla.

Por lo mismo, preferí profundizar el modelo App Shell y PRPL, que son elementos que nos permitirán armar una estructura para nuestra PWA que nos ayude en el desafío de hacer nuestras aplicaciones cada vez más rápidas, incluso pensando en conexiones 3G o hasta sin conexión (aunque para esto necesitaremos los service workers que veremos en una siguiente historia).

El modelo App Shell

La mejora en la experiencia de usuario web desde dispositivos móviles es algo que persiguen las PWA. Un elemento fundamental para esta mejora, es acercarse lo más posible a la experiencia de una aplicación nativa.

Cuando pensamos en una aplicación nativa, para efectos de esta explicación, podemos ver las siguientes ventajas o características que nos gustaría imitar en una PWA:

  • Rapidez y confiabilidad. Las vistas pueden ser extremadamente rápidas al cargar y comenzar a utilizar.
  • Uso económico de datos. Cuando usamos una app nativa, descargamos sus binarios una primera vez y luego, en cada petición se buscan solo los datos que se necesitan actualizar, no páginas HTML, CSS, JS y assets, como lo haría una aplicación web tradicional.
Una arquitectura de “aplicación shell”, básicamente, es el HTML, CSS y Javascript mínimo que soporta la interfaz de una aplicación, es decir son los recursos básicos que la aplicación web necesita para cargar el esqueleto de la interfaz de usuario UI. Esto permite que las Aplicaciones Web Progresivas se carguen de forma instantánea y fiable de manera similar a las aplicaciones nativas.

El patrón PRPL

Este patrón es nuevo y está en desarrollo, y va mas allá de todos los objetivos y estándares de las Aplicaciones Web Progresivas, tiene relación con una visión a largo plazo de mejora del rendimiento de la web móvil. Básicamente busca hacer que el usuario pueda disfrutar/interactuar del contenido en el menor tiempo posible.

El desglose del acrónimo es:

  • Push. Empaquetado de recursos críticos para la ruta de la URL inicial. Esto sería el App Shell para el inicio de la aplicación.
  • Render. Despliegue rápido de la ruta inicial.
  • Pre cache. Consiste en cachear anticipadamente recursos que creamos que van a ser usados luego por el usuario.
  • Lazy load. Carga de recursos bajo demanda y según se vayan necesitando.

Cada elemento del patrón es beneficioso por si mismo, así que podemos utilizar cualquiera de forma independiente.

Estructura de la aplicación

Para una arquitectura SPA, el patrón PRPL puede funcionar con la siguiente estructura:

  • Un entrypoint principal que está disponible desde cualquier ruta válida de la aplicación. Este archivo debe ser muy pequeño, ya que estará disponible desde distintas URLs y puede almacenarse en cache muchas veces. Además, todas las URLs de recursos en el entrypoint tienen que ser absolutas porque el entrypoint puede estar en rutas que no son de primer nivel de la aplicación.
  • El app shell, con el esqueleto de primer nivel de la aplicación y el ruteo a secciones con carga on demand.
  • Fragmentos cargados bajo demanda de los cuales el app shell se encarga de importar y cargar dinámicamente.

Un pequeño ejemplo práctico

Probaremos con un proyecto simple con VueJS y Webpack, utilizando una plantilla de vue-cli para PWA. Primero, instalamos vue-cli en caso de no tenerlo.

npm install -g vue-cli

Luego, para generar la aplicación

vue init pwa vue-app-shell

Debemos hacer las siguientes configuraciones iniciales y ya tendremos la estructura inicial de nuestra PWA.

Instalamos las dependencias de la aplicación con

cd vue-app-shellnpm install

Luego, abrimos el código generado con nuestro editor o IDE favorito, en este caso IntelliJ IDEA. En la raíz de src, tenemos App.vue que es el componente encargado de renderizar el layout por defecto de la aplicación, sería el App Shell. En el tag router-view es donde Vue carga el contenido dinámico de la aplicación.

src/App.vue

Hasta aquí, tenemos un App Shell que tiene básicamente el logo de Vue, un header y unos estilos.

Si revisamos el router, tenemos el componente por defecto Hello para la ruta raíz. Agregaremos 2 rutas más para 2 nuevas vistas para probar esta prueba. Creamos los componentes Opcion1 y Opcion2, para efectos de este ejemplo como copias del componente Hello.

src/router/index.js

Luego de incorporar estos nuevos componentes y rutas, hagamos un build de la aplicación para ver cómo quedaría en producción.

npm run build
dist/static/js

En la imagen, se pueden ver los bundles generados por webpack, en los que se separa la lógica de la aplicación de las dependencias de terceros. Para el caso del app.*.js en el se encuentra empaquetado todo el código javascript de la aplicación, en este caso todos los componentes (Hello, Opcion1 y Opcion2). En el index.html generado se importan estos bundles, y esto hace que en la carga inicial de la aplicación, se deba bajar todo este código para luego desplegar la vista.

Para optimizar la carga de los componentes utilizamos la carga on demand de webpack para cada módulo. Esto lo hacemos en el router de la siguiente manera:

Si hacemos el build nuevamente, Webpack interpretará lo anterior y generará bundles para cada componente importado de forma Lazy.

npm run build

Al hacer el build, webpack genera los bundles 0.*, 1.* y 2.* para cada uno de los componentes, los cuales son cargados de manera diferida solo cuando se necesitan. Esto es mucho más eficiente.

dist/static/js


Con esto tenemos un ejemplo simple de App Shell con carga lazy de las librerías. esto se le puede agregar Service Workers y un mecanismo de precache de recursos. Esto quedará para un próximo artículo.