Fuente: Este artículo se publicó en inglés originalmente en Smashing Magazine, el autor es Kevin Farrugia y el título original es «A Beginner’s Guide To Progressive Web Apps». Se ha hecho una traducción libre al español. Las imágenes y referencias se han mantenido en el idioma original.

Las aplicaciones web progresivas podrían ser la próxima sorpresa para la web móvil.

Originalmente propuestas por Google en 2015, ya han atraído mucha atención debido a la relativa facilidad de desarrollo y las victorias casi instantáneas para la experiencia de usuario. Una aplicación web progresiva aprovecha las últimas tecnologías para combinar lo mejor de las aplicaciones web y las aplicaciones móviles.

Piensa en ellas como en un sitio web construido utilizando tecnologías web, pero que actúa y se siente como una aplicación.

Los recientes avances en los navegadores, la disponibilidad de los service workers y los adelantos en las API de Caché y Push han facilitado que los desarrolladores web puedan permitir a los usuarios instalar aplicaciones web en sus pantallas de inicio, recibir notificaciones push e incluso trabajar sin conexión.

Las aplicaciones web progresivas aprovechan el ecosistema web, los complementos, las comunidades mucho más grandes y la relativa facilidad de implementación y mantenimiento de un sitio web en comparación con una aplicación nativa de las tiendas de aplicaciones respectivas.

Aquellos de nosotros que desarrollamos tanto para el móvil como para la web encontramos en ellas significativas ventajas, como que un sitio web se pueda construir en menos tiempo, que una API no necesite ser mantenida con compatibilidad hacia atrás (todos los usuarios ejecutarán la misma versión del sitio web, a diferencia de la fragmentación de versiones de las aplicaciones nativas) y que la aplicación generalmente sea más fácil de implementar y mantener.

¿Por qué las aplicaciones web progresivas?

Un estudio ha demostrado que, en promedio, una aplicación pierde 20% de sus usuarios por cada paso entre el primer contacto del usuario con la aplicación y el comenzar a utilizarla. El usuario debe encontrar primero la aplicación en una tienda de aplicaciones, luego descargarla, instalarla y finalmente, abrirla. Cuando un usuario encuentra una aplicación web progresiva, puede comenzar a utilizarla inmediatamente, eliminando las etapas innecesarias de descarga e instalación.

Sin embargo, una aplicación nativa definitivamente no es mala del todo. Las aplicaciones móviles con notificaciones push logran hasta tres veces más retención que sus contrapartes sin push y un usuario tiene tres veces más probabilidades de reabrir una aplicación móvil que un sitio web. Además, una aplicación móvil bien diseñada consume menos datos y es mucho más rápida porque algunos recursos residen en el dispositivo.

Ahora bien, una aplicación web progresiva aprovecha las características de una aplicación móvil, lo que resulta en una mayor retención y rendimiento del usuario, pero sin las complicaciones que implica mantener una aplicación móvil.

Casos de uso

¿Cuándo deberías crear una aplicación web progresiva? Normalmente, se recomienda hacer aplicaciones nativas para aplicaciones en las que espera que los usuarios vuelvan con frecuencia y una aplicación web progresiva no es diferente.

Flipkart utiliza una aplicación web progresiva para su popular plataforma de comercio electrónico, Flipkart Lite. Y Air Berlin utiliza una para su proceso de check-in en línea, lo que permite a los usuarios acceder a sus tickets sin conexión a Internet.

Al evaluar si tu próxima aplicación debe ser una aplicación web progresiva, un sitio web o una aplicación móvil nativa, primero identifica a tus usuarios y las acciones más importantes que ejecutarán. Al ser «progresiva», una aplicación web funciona en todos los navegadores y la experiencia se mejora cada vez que se actualiza el navegador del usuario con características y APIs nuevas o mejoradas.

Por lo tanto, no hay compromiso en la experiencia de usuario con una aplicación web progresiva en comparación con un sitio web tradicional; Sin embargo, puede que debas decidir qué funcionalidad soportar sin conexión, y tendrás que facilitar la navegación (recuerda que en modo independiente, el usuario no tiene acceso al botón Atrás). Si tu sitio web ya tiene una interfaz similar a la aplicación, el uso de los conceptos de las aplicaciones web progresivas sólo lo hará mejor.

Si se requieren ciertas funciones para las acciones críticas de los usuarios, pero aún no están disponibles para web debido a la falta de compatibilidad entre navegadores, una aplicación móvil nativa podría ser la mejor opción, garantizando así la misma experiencia para todos los usuarios.

Características de un vínculo de aplicación web progresiva

Antes de ir al código, es importante entender que las aplicaciones web progresivas tienen las siguientes características:

Progresiva
Por definición, una aplicación web progresiva debe funcionar en cualquier dispositivo y aumentar progresivamente, aprovechando las funciones disponibles en el dispositivo del usuario y el navegador.

Descubrible
Debido a que una aplicación web progresiva es un sitio web, debe ser detectable por los motores de búsqueda. Esta es una gran ventaja sobre las aplicaciones nativas, que todavía se quedan atrás de los sitios web en las búsquedas.

Enlazable
Como otra característica heredada de sitios web, un sitio web bien diseñado debe utilizar el URI para indicar el estado actual de la aplicación. Esto permitirá a la aplicación web conservar o recargar su estado cuando el usuario guarde en marcadores o comparta la URL de la aplicación.

Sensible
La interfaz de usuario de una aplicación web progresiva debe ajustarse al factor de forma y al tamaño de la pantalla de cada dispositivo.

App-like
Una aplicación web progresiva debe parecerse a una aplicación nativa y debe estar basada en el modelo shell de aplicaciones, con un mínimo de actualizaciones de página.

Conectividad independiente
Debe funcionar en áreas de baja conectividad o fuera de línea (nuestra característica favorita).

Re-enganchable
Los usuarios de aplicaciones móviles tienen más probabilidades de reutilizar sus aplicaciones y las aplicaciones web progresivas tienen la intención de lograr los mismos objetivos a través de funciones como notificaciones push.

Instalable
Una aplicación web progresiva se puede instalar en la pantalla principal del dispositivo, lo que la hace fácilmente disponible.

Fresca
Cuando se publica un nuevo contenido y el usuario está conectado a Internet, dicho contenido debe estar disponible en la aplicación.

Segura
Debido a que una aplicación web progresiva tiene una experiencia de usuario más íntima y porque todas las solicitudes de red pueden ser interceptadas a través de los service workers, es imprescindible que la aplicación sea alojada a través de HTTPS para evitar ataques malintencionados en el medio.

Vamos al Código

Nuestra primera aplicación web progresiva, Sky High, simulará el horario de llegadas de vuelos en un aeropuerto. La primera vez que el usuario accede a ella, queremos mostrarle una lista de los próximos vuelos recuperados de una API. Si el usuario no tiene una conexión a Internet y vuelve a cargar la aplicación web, queremos mostrarle el horario de vuelo tal como era cuando lo descargó por última vez con una conexión.

Sky High, nuestra aplicación web progresiva ficticia

Los fundamentos

La primera característica de una aplicación web progresiva es que debe funcionar en todos los dispositivos y debe mejorar en los dispositivos y los navegadores que lo permitan. Por lo tanto, hemos creado nuestro sitio web utilizando HTML5 tradicional con JavaScript que simula la recuperación de datos de una API simulada.

A lo largo de la aplicación, vamos a utilizar algo de Knockout para manejar nuestros enlaces Model-View-ViewModel (MVVM) – es un framework de JavaScript ligero que nos permite vincular nuestros modelos de JavaScript a nuestras vistas HTML.

Optamos por usar Knockout porque es relativamente simple de entender y no trae desorden en el código. Sin embargo en tu código lo puedes reemplazar con cualquier otro framework como React o AngularJS.

Nuestro sitio web sigue las directrices de Material Design de Google, un conjunto de principios que guían el diseño y la interacción. Material Design no sólo sirve como un estándar unificado entre aplicaciones y dispositivos, sino que también da un significado de diseño. Hemos utilizado Material Design para la vista de llegadas de Sky High para darle a nuestra aplicación web la apariencia y el look and feel de una aplicación nativa.

Por último, hemos probado nuestra aplicación para asegurarnos de que es jank-free (asegura el tiempo de carga de la interface y evita parpadeos o bloqueos) y que el desplazamiento es suave. El render de jank-free ha demostrado que mejora el compromiso del usuario. Lo preparamos para un render de 60 frames por segundo.

Para este demo, recuperaremos un archivo JSON estático, en lugar de una API real. Esto es para mantener las cosas simples. En el mundo real deberías consultar una API o usar WebSockets.

index.html

<!DOCTYPE html>
<html lang="en">


<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Sky-High Airport Arrivals</title>
    <link async rel="stylesheet" href="./css/style.css">
    <link href="https://fonts.googleapis.com/css?family=Roboto:300,600,300italic,600italic" rel="stylesheet" type="text/css">
</head>


<body>
    <header>
        <div class="content">
            <h3>Arrivals</h3>
        </div>
    </header>
    <div class="container">
        <div id="main" class="content">
            <ul class="arrivals-list" data-bind="foreach: arrivals">
                <li class="item">
                    <span class="title" data-bind="html: title"></span>
                    <span class="status" data-bind="html: status"></span>
                    <span class="time" data-bind="html: time"></span>
                </li>
            </ul>
        </div>
    </div>
    <script src="./js/build/vendor.min.js"></script>
    <script src="./js/build/script.min.js"></script>
</body>


</html>

El archivo index.html es relativamente estándar. Hemos creado una lista HTML y hemos enlazado a ella la propiedad arrivals de nuestro View Model Llegadas usando Knockout, a través del atributo data-bind = «foreach: arrivals». El view model Llegadas se declaró en el archivo page.js que se muestra a continuación y está expuesto en el módulo Página. En nuestra página HTML, para cada elemento de la matriz de llegadas, hemos enlazado las propiedades de título, estado y tiempo a la vista HTML.

page.js

(var Page = (function() {


    // declare the view model used within the page
    function ViewModel() {
        var self = this;
        self.arrivals = ko.observableArray([]);
    }


    // expose the view model through the Page module
    return {
        vm: new ViewModel(),
        hideOfflineWarning: function() {
            // enable the live data
            document.querySelector(".arrivals-list").classList.remove('loading')
            // remove the offline message
            document.getElementById("offline").remove();
            // load the live data
        },
        showOfflineWarning: function() {
            // disable the live data
            document.querySelector(".arrivals-list").classList.add('loading')
                // load html template informing the user they are offline
            var request = new XMLHttpRequest();
            request.open('GET', './offline.html', true);


            request.onload = function() {
                if (request.status === 200) {
                    // success
                    // create offline element with HTML loaded from offline.html template
                    var offlineMessageElement = document.createElement("div");
                    offlineMessageElement.setAttribute("id", "offline");
                    offlineMessageElement.innerHTML = request.responseText;
                    document.getElementById("main").appendChild(offlineMessageElement);
                } else {
                    // error retrieving file
                    console.warn('Error retrieving offline.html');
                }
            };


            request.onerror = function() {
                // network errors
                console.error('Connection error');
            };


            request.send();
        }
    }


})();

Este archivo page.js expone el módulo Page, que contiene nuestro ViewModel vm y 2 funciones, hideOfflineWarning y showOfflineWarning. El View Model ViewModel es un simple literal de JavaScript que se utilizará en toda la aplicación.

Las propiedad arrivals(llegadas) en el ViewModel es un observableArray de Knockout que enlaza automáticamente nuestro HTML a un array de JavaScript, lo que nos permite empujar y colocar elementos en nuestro array en JavaScript y actualizar automáticamente el HTML de la página.

Las funciones hideOfflineWarning y showOfflineWarning, al ser llamadas, permiten al resto de nuestra aplicación actualizar la interfaz de usuario de la página que muestra si estamos conectados en línea. La función showOfflineWarning añade una clase de carga a nuestro elemento HTML de lista de llegadas para atenuar la lista con un efecto fade y a continuación, recupera el archivo HTML offline.html a través de XHR. Suponiendo que el archivo se ha recuperado satisfactoriamente (response.status === 200), añadimos esto a nuestro HTML. Por supuesto, si no estamos utilizando a los service workers y el usuario no está conectado a Internet, entonces no sería posible recuperar offline.html, por lo que el usuario vería en ese caso únicamente la página fuera de línea del navegador.

La lógica de negocio desde donde recuperamos los datos de nuestra API y lo enlazamos a nuestros ViewModels y Vistas se encuentra en arrivals.js y es la funcionalidad estándar de MVVM con Knockout. En el archivo arrivals.js, simplemente inicializamos los servicios y View Models que usaremos en toda la aplicación, y exponemos una función – Arrivals.loadData () – que recupera los datos y los enlaza al modelo de vista.

Manifiesto de Aplicación Web

Hagamos que nuestra aplicación web sea más parecida a una aplicación. Un archivo de manifiesto de aplicación web es un archivo JSON simple que sigue la especificación del W3C. Con él, es posible ejecutar la aplicación web en modo de pantalla completa como una aplicación independiente, asignar un icono que se mostrará cuando se instale la aplicación en el dispositivo y asignar un tema y un color de fondo a la aplicación. Además, Chrome en Android sugerirá proactivamente que el usuario instale la aplicación web, mediante un banner de instalación de aplicación web. Para mostrar el mensaje de instalación, tu aplicación web debe tener lo siguiente:

  • Un archivo de manifiesto de aplicación web válido,
  • Ser servido a través de HTTPS,
  • Tener registrado un service worker válido,
  • Haber sido visitado dos veces, con al menos cinco minutos entre cada visita

Banner de instalación de aplicaciones web

manifest.json

{
    "short_name": "Arrivals",
    "name": "Arrivals at Sky High",
    "description": "Progressive web application demonstration",
    "icons": [
        {
            "src": "launcher-icon.png",
            "sizes": "48x48",
            "type": "image/png"
        },
        {
            "src": "launcher-icon-96.png",
            "sizes": "96x96",
            "type": "image/png"
        },
        {
            "src": "launcher-icon-144.png",
            "sizes": "144x144",
            "type": "image/png"
        },
        {
            "src": "launcher-icon-192.png",
            "sizes": "192x192",
            "type": "image/png"
        },
        {
            "src": "launcher-icon-256.png",
            "sizes": "256x256",
            "type": "image/png"
        }
    ],
    "start_url": "./?utm_source=web_app_manifest",
    "display": "standalone",
    "orientation": "portrait",
    "theme_color": "#29BDBB",
    "background_color": "#29BDBB"
}

Vamos a desglosar este archivo de manifiesto:

  • Short_name es un nombre legible para la aplicación. En Chrome para Android, este también es el nombre del icono en la pantalla de inicio.
  • name también es un nombre legible para la aplicación y define cómo se mostrará la aplicación.
  • description proporciona una descripción general de la aplicación web.
  • icons define una matriz de imágenes de diferentes tamaños que servirán como conjunto de iconos de la aplicación. En Chrome para Android, el icono se utilizará en la pantalla de bienvenida, en la pantalla de inicio y en el selector de tareas.
  • start_url es la URL inicial de la aplicación.
  • display define el modo de visualización predeterminado para la aplicación web: pantalla completa, independiente, mínimo-ui o navegador.
  • orientation define la orientación predeterminada para la aplicación web: vertical u horizontal.
  • theme_color es el color predeterminado del tema para la aplicación. En Android, también se utiliza para colorear la barra de estado.
  • background_color define el color de fondo de la aplicación web. En Chrome, también define el color de fondo de la pantalla de bienvenida.
  • related_applications no se implementa en nuestro ejemplo pero se utiliza para especificar alternativas de aplicación nativas en las distintas tiendas de aplicaciones.

Tienes que agregar la referencia manifest.json a la etiqueta principal del archivo index.html:

<link rel=«manifest» href =«./ manifest.json»>

Una vez que un usuario ha añadido la aplicación web a su pantalla de inicio, podrá volver a conectar con tu aplicación de inmediato desde su dispositivo sin tener que abrir directamente el navegador. Aquí puedes ver cómo esto es mucho más que un marcador de navegador web.

Más detalles en este Video.

Service Workers

Uno de los aspectos más emocionantes de las aplicaciones web progresivas es que pueden trabajar sin conexión. Utilizando a los Service Workers, es posible mostrar datos recuperados en sesiones anteriores de la aplicación (utilizando IndexedDB) o, alternativamente, mostrar el shell de la aplicación e informar al usuario que no está conectado a Internet (el enfoque que hemos tomado en esta demostración). Una vez que el usuario se vuelve a conectar, podemos recuperar los datos más recientes del servidor.

Todo esto es posible a través de los Service Workers, que son scripts dirigidos por eventos (escritos en JavaScript) que tienen acceso a eventos domain-wide, incluyendo recuperación de red. Con ellos, podemos almacenar en caché todos los recursos estáticos, lo que podría reducir drásticamente las solicitudes de red y mejorar el rendimiento considerablemente.

Shell de la aplicación

El shell de la aplicación es el mínimo HTML, CSS y JavaScript necesarios para alimentar una interfaz de usuario. Una aplicación móvil nativa incluye el shell de aplicación como parte de su distribución, mientras que los sitios web normalmente lo solicitan a través de la red. Las aplicaciones web progresivas superan esta brecha colocando los recursos del shell de la aplicación en la caché del navegador. En nuestra aplicación Sky High, podemos ver que nuestro shell de aplicación consta de la barra de encabezado superior, las fuentes y cualquier CSS requerido para renderizarlas de manera elegante.

Para comenzar con los Service Workers, primero necesitamos crear el archivo JavaScript de nuestro Service Worker, sw.js ubicado en el directorio raíz.

sw.js

// Use a cacheName for cache versioning
var cacheName = 'v1:static';


// During the installation phase, you'll usually want to cache static assets.
self.addEventListener('install', function(e) {
    // Once the service worker is installed, go ahead and fetch the resources to make this work offline.
    e.waitUntil(
        caches.open(cacheName).then(function(cache) {
            return cache.addAll([
                './',
                './css/style.css',
                './js/build/script.min.js',
                './js/build/vendor.min.js',
                './css/fonts/roboto.woff',
                './offline.html'
            ]).then(function() {
                self.skipWaiting();
            });
        })
    );
});


// when the browser fetches a URL…
self.addEventListener('fetch', function(event) {
    // … either respond with the cached object or go ahead and fetch the actual URL
    event.respondWith(
        caches.match(event.request).then(function(response) {
            if (response) {
                // retrieve from cache
                return response;
            }
            // fetch as normal
            return fetch(event.request);
        })
    );
});

Miremos más de cerca a nuestro Service Worker. En primer lugar, estamos estableciendo una variable cacheName. Esto se utiliza para determinar si se han realizado cambios en nuestros archivos assets almacenados en caché. Para este ejemplo, usaremos un nombre estático, lo que significa que nuestros archivos no cambiarán o requerirán actualizaciones.

self.addEventListener(‘install’, function(e) {
// declare which assets to cache
}

El evento install se desencadena durante la fase de instalación del Service Worker y se disparará sólo una vez si el Service Worker ya está instalado. Por lo tanto, actualizar la página no activará de nuevo la fase de instalación. Durante ella, podemos declarar los assets que se almacenarán en caché. En nuestro ejemplo anterior, estamos almacenando en caché un archivo CSS, dos archivos JavaScript, nuestro archivo de fuentes, nuestra plantilla HTML sin conexión y, por supuesto, la raíz de la aplicación. self.skipWaiting () obliga al Service Worker en espera a ponerse activo.

Hasta ahora, hemos declarado a nuestro Service Worker, pero antes de que entre en efecto, necesitamos referenciarlo en nuestro JavaScript. En nuestra aplicación, lo registramos en main.js

main.js

// Register the service worker if available.
if ('serviceWorker' in navigator) {
    navigator.serviceWorker.register('./sw.js').then(function(reg) {
        console.log('Successfully registered service worker', reg);
    }).catch(function(err) {
        console.warn('Error whilst registering service worker', err);
    });
}


window.addEventListener('online', function(e) {
    // Resync data with server.
    console.log("You are online");
    Page.hideOfflineWarning();
    Arrivals.loadData();
}, false);


window.addEventListener('offline', function(e) {
    // Queue up events for server.
    console.log("You are offline");
    Page.showOfflineWarning();
}, false);


// Check if the user is connected.
if (navigator.onLine) {
    Arrivals.loadData();
} else {
    // Show offline message
    Page.showOfflineWarning();
}


// Set Knockout view model bindings.
ko.applyBindings(Page.vm);

También hemos incluido dos event listeners para comprobar si el estado de la sesión ha cambiado de online a offline o viceversa. Los manejadores de eventos llaman luego a las diferentes funciones para recuperar los datos a través de Arrivals.loadData() y para habilitar o deshabilitar el mensaje de sin conexión a través de Page.showOfflineWarning y Page.hideOfflineWarning, respectivamente.

Nuestra aplicación también comprueba si el usuario está actualmente en línea, usando navigator.onLine, y recupera los datos o muestra la advertencia offline en consecuencia. Y en la última línea de main.js, aplicamos los enlaces de Knockout a nuestra página View Model Page.vm

Si cargamos nuestra aplicación por primera vez (con las Herramientas para desarrolladores de Chrome), no veremos nada nuevo. Sin embargo, al volver a cargar, veremos que se han recuperado varios recursos de la red del Service Worker. Este es nuestro shell de aplicación.

Recursos de red del shell de aplicaciones, en las herramientas de desarrollo de Chrome

Prueba sin conexión

Un usuario que ejecuta la aplicación sin una conexión a Internet (suponiendo que ya ha estado en la página) simplemente obtendrá el shell de la aplicación y se mostrará la advertencia fuera de línea. Esto es una mejora sobre el recurso t-rex de Chrome. Una vez que el usuario ha establecido una conexión de red, desactivamos la advertencia y recuperamos los datos más recientes.

Renderizar una página HTML personalizada en lugar de la página predeterminada de Chrome

Notificaciones Push

Las notificaciones push permiten a los usuarios optar por actualizaciones oportunas de las aplicaciones en las que confían, lo que les ayuda a volver a confiar en ellas. Las notificaciones Push (de inserción) en la Web te permiten interactuar con tu audiencia incluso cuando el navegador está cerrado.

Notificaciones push en Emojoy

La API Push es compatible con Chrome, Opera y el navegador de Samsung y está en desarrollo en Firefox y Microsoft Edge. Desafortunadamente, no hay ninguna indicación de que la característica se vaya a implementar en Safari.

Rendimiento

Una de las virtudes de los Service Worker es que podemos mejorar el rendimiento con poco o ningún esfuerzo. Si comparamos nuestro sitio web con lo que había antes de que los Service Workers se implementaran, antes había que recuperar más de 200 KB al cargar la página, lo cual ahora se reduce a 13 KB. En una red 3G regular, la pagina habría tardado 3,5 segundos en cargarse; ahora se tarda 500 milisegundos.

Estas mejoras de rendimiento son drásticas porque la aplicación en sí es muy pequeña y tiene funcionalidad limitada. Sin embargo, a través del uso correcto del almacenamiento en caché, es posible mejorar significativamente el rendimiento y el rendimiento percibido, especialmente para los usuarios en lugares con baja conectividad.

Lighthouse

El equipo de Chrome de Google ha creado una herramienta para probar aplicaciones web progresivas. Lighthouse se ejecuta en Node.js o como un plugin de Chrome y se puede encontrar también en GitHub.

Para ejecutar una prueba de Lighthouse, tu sitio web debe estar disponible en línea, lo que significa que no se puede probar en localhost.

Para empezar, descarga el paquete npm:

npm install -g GoogleChrome/lighthouse

Una vez instalado, ejecuta Chrome

npm explore -g lighthouse — npm run chrome lighthouse https://incredibleweb.github.io/pwa-tutorial/

La ejecución de Lighthouse estará visible en la línea de comandos y clasificará tu sitio web según las características y propiedades progresivas de la aplicación web que hayas implementado. Por ejemplo, si está utilizando un archivo manifest.json o si tu página está disponible sin conexión.

Soporte entre navegadores

Estamos todavía en los primeros días de las aplicaciones web progresivas, y el soporte cross-browser es aún limitado, especialmente en Safari y Edge. Sin embargo, Microsoft soporta abiertamente aplicaciones web progresivas y debería estar implementando más funciones a finales de año.

Service workers y Cache API
Compatible con Chrome, Firefox, Opera y el navegador de Samsung. En desarrollo en Microsoft Edge, se espera que esté disponible a finales de 2016. En Safari está bajo consideración.

Añadir a la pantalla principal
Compatible con Chrome, Firefox, Opera, Android Browser y el navegador de Samsung. Microsoft parece indicar que las aplicaciones web progresivas estarán disponibles como listados de tiendas. No hay planes para Safari hasta el momento.

Push API
La mayoría son compatibles con Chrome, Firefox, Opera y el navegador de Samsung. En desarrollo en Microsoft Edge. No hay planes para Safari hasta el momento.

Si más desarrolladores aprovechan las características que ofrecen las aplicaciones web progresivas, que son relativamente fáciles de implementar y proporcionan recompensas inmediatas, los usuarios preferirán consumir estas aplicaciones web en navegadores compatibles y habrá esperanza de convencer a otros proveedores de navegadores para que se adapten.

Conclusión

Este artículo es simplemente un aperitivo para empezar con aplicaciones web progresivas. Podríamos hacer mucho más para crear una experiencia similar a la aplicación que buscan los usuarios, ya sea al apoyar notificaciones push con el Push API, hacer que la aplicación se vuelva a activar o utilizar IndexedDB y hacer sincronización de fondo para mejorar la experiencia sin conexión.

Enlace al código fuente

El código fuente completo de este tutorial está disponible en un repositorio de Github, y la demo está disponible en GitHub Pages.