Mainline es una tienda minorista de ropa en línea que ofrece las marcas de diseñadores más importantes de la moda. La empresa con sede en el Reino Unido confía en su equipo de expertos internos, combinado estratégicamente con socios clave, para brindar una experiencia de compra sin inconvenientes para todos. Con una presencia en el mercado en más de 100 países a través de siete sitios web territoriales personalizados y una app, Mainline seguirá garantizando que la oferta de comercio electrónico compita con la competencia.
Desafío
El objetivo de Mainline Menswear era complementar el sitio web actual optimizado para dispositivos móviles con funciones progresivas que se ajustaran a su visión de "prioridad para los dispositivos móviles", enfocándose en el diseño y la funcionalidad compatibles con dispositivos móviles, teniendo en cuenta un mercado de teléfonos inteligentes en crecimiento.
Solución
El objetivo era compilar y lanzar una AWP que complementara la versión original del sitio web de Mainline Menswear, que es compatible con dispositivos móviles, y, luego, comparar las estadísticas con su app híbrida para dispositivos móviles, que actualmente está disponible en Android y iOS.
Una vez que se lanzó la app y la usaban una pequeña sección de usuarios de Mainline Menswear, pudieron determinar la diferencia en las estadísticas clave entre la AWP, la app y la Web.
El enfoque que adoptó Mainline cuando convirtió su sitio web en una AWP fue asegurarse de que el framework que seleccionaban para su sitio web (Nuxt.js, con Vue.js) fuera preparado para el futuro y le permitiría aprovechar la tecnología web rápida.
Resultados
139%
Más páginas por sesión en la AWP en comparación con la Web
161%
Mayor duración de las sesiones en la AWP que en la Web
10%
Porcentaje de rebote más bajo en la AWP en comparación con la Web
12.5%
Valor promedio del pedido más alto en la AWP en comparación con la Web
55%
de aumento en el porcentaje de conversiones en AWP en comparación con la Web
El 243%
Mayores ingresos por sesión en la AWP en comparación con la Web
Información técnica detallada
Mainline Menswear usa el framework Nuxt.js para agrupar y renderizar su sitio, que es una aplicación de una sola página (SPA).
Genera un archivo de trabajador de servicio
Para generar el trabajador de servicio, Mainline Menswear agregó configuración a través de una implementación personalizada del módulo nuxt/pwa
Workbox.
El motivo por el que crearon una bifurcación del módulo nuxt/pwa
fue para permitir que el equipo agregara más personalizaciones al archivo del trabajador de servicio que no podía o tenía problemas cuando usaba la versión estándar.
Una de esas optimizaciones se centró en la funcionalidad sin conexión del sitio, como, por ejemplo, publicar una página sin conexión predeterminada y recopilar estadísticas sin conexión.
Anatomía del manifiesto de la app web
El equipo generó un manifiesto con íconos para diferentes tamaños de íconos de apps para dispositivos móviles y otros detalles de apps web, como name
, description
y theme_color
:
{
"name": "Mainline Menswear",
"short_name": "MMW",
"description": "Shop mens designer clothes with Mainline Menswear. Famous brands including Hugo Boss, Adidas, and Emporio Armani.",
"icons": [
{
"src": "/_nuxt/icons/icon_512.c2336e.png",
"sizes": "512x512",
"type": "image/png"
}
],
"theme_color": "#107cbb"
}
Una vez instalada, la app web se puede iniciar desde la pantalla principal sin que el navegador estorbe. Para ello, agrega el parámetro display
en el archivo de manifiesto de la app web:
{
"display": "standalone"
}
Por último, la empresa ahora puede hacer un seguimiento sencillo de la cantidad de usuarios que visitan su app web desde la pantalla principal con solo agregar un parámetro utm_source
en el campo start_url
del manifiesto:
{
"start_url": "/?utm_source=pwa"
}
Almacenamiento en caché del entorno de ejecución para navegaciones más rápidas
El almacenamiento en caché de apps web es fundamental para optimizar la velocidad de la página y brindar una mejor experiencia del usuario a los usuarios recurrentes.
Para almacenar en caché en la Web, hay varios enfoques diferentes. El equipo usa una combinación de la caché HTTP y la API de Cache para almacenar los recursos en caché en el lado del cliente.
La API de Cache le brinda a Mainline Menswear un control más preciso sobre los recursos almacenados en caché, lo que les permite aplicar estrategias complejas a cada tipo de archivo. Si bien todo esto suena complicado y difícil de configurar y mantener, Workbox les proporciona una manera fácil de declarar estrategias tan complejas y facilita la molestia del mantenimiento.
Almacenamiento en caché de CSS y JS
En el caso de los archivos CSS y JS, el equipo decidió almacenarlos en caché y entregarlos a través de la caché con la estrategia de Workbox StaleWhileRevalidate
. Esta estrategia les permite entregar todos los archivos CSS y JS de Nuxt con rapidez, lo que aumenta significativamente el rendimiento de su sitio.
Al mismo tiempo, los archivos se actualizan en segundo plano a la versión más reciente para la próxima visita:
/* sw.js */
workbox.routing.registerRoute(
/\/_nuxt\/.*(?:js|css)$/,
new workbox.strategies.StaleWhileRevalidate({
cacheName: 'css_js',
}),
'GET',
);
Almacenamiento en caché de fuentes de Google
La estrategia para almacenar en caché Google Fonts depende de dos tipos de archivos:
- La hoja de estilo que contiene las declaraciones
@font-face
. - Los archivos de fuentes subyacentes (solicitados en la hoja de estilo mencionada anteriormente).
// Cache the Google Fonts stylesheets with a stale-while-revalidate strategy.
workbox.routing.registerRoute(
/https:\/\/fonts\.googleapis\.com\/*/,
new workbox.strategies.StaleWhileRevalidate({
cacheName: 'google_fonts_stylesheets',
}),
'GET',
);
// Cache the underlying font files with a cache-first strategy for 1 year.
workbox.routing.registerRoute(
/https:\/\/fonts\.gstatic\.com\/*/,
new workbox.strategies.CacheFirst({
cacheName: 'google_fonts_webfonts',
plugins: [
new workbox.cacheableResponse.CacheableResponsePlugin({
statuses: [0, 200],
}),
new workbox.expiration.ExpirationPlugin({
maxAgeSeconds: 60 * 60 * 24 * 365, // 1 year
maxEntries: 30,
}),
],
}),
'GET',
);
Almacenar imágenes en caché
En el caso de las imágenes, Mainline Menswear decidió utilizar dos estrategias. La primera estrategia se aplica a todas las imágenes que provienen de su CDN, que, por lo general, son imágenes de productos. Sus páginas tienen muchas imágenes, por lo que se esfuerzan por no ocupar demasiado espacio de almacenamiento en los dispositivos de los usuarios. Por lo tanto, a través de Workbox, agregaron una estrategia que almacena en caché las imágenes que provienen solo de su CDN con un máximo de 60 imágenes mediante ExpirationPlugin
.
La imagen 61 (la más reciente) solicitada reemplaza a la 1 (la más antigua) para que no se almacenen en caché más de 60 imágenes de productos en ningún momento.
workbox.routing.registerRoute(
({ url, request }) =>
url.origin === 'https://mainline-menswear-res.cloudinary.com' &&
request.destination === 'image',
new workbox.strategies.StaleWhileRevalidate({
cacheName: 'product_images',
plugins: [
new workbox.expiration.ExpirationPlugin({
// Only cache 60 images.
maxEntries: 60,
purgeOnQuotaError: true,
}),
],
}),
);
La segunda estrategia de imágenes controla el resto de las imágenes que solicita el origen. Estas imágenes tienden a ser muy pocas y pequeñas en todo el origen, pero, para mayor seguridad, la cantidad de estas imágenes almacenadas en caché también se limita a 60.
workbox.routing.registerRoute(
/\.(?:png|gif|jpg|jpeg|svg|webp)$/,
new workbox.strategies.StaleWhileRevalidate({
cacheName: 'images',
plugins: [
new workbox.expiration.ExpirationPlugin({
// Only cache 60 images.
maxEntries: 60,
purgeOnQuotaError: true,
}),
],
}),
);
Cómo proporcionar funcionalidad sin conexión
La página sin conexión se almacena en caché de antemano justo después de que se instala y activa el service worker. Para ello, crean una lista de todas las dependencias sin conexión: el archivo HTML sin conexión y un ícono SVG sin conexión.
const OFFLINE_HTML = '/offline/offline.html';
const PRECACHE = [
{ url: OFFLINE_HTML, revision: '70f044fda3e9647a98f084763ae2c32a' },
{ url: '/offline/offline.svg', revision: 'efe016c546d7ba9f20aefc0afa9fc74a' },
];
Luego, la lista de almacenamiento en caché se envía a Workbox, que se encarga de todo el trabajo pesado de agregar las URLs a la caché, verificar si hay alguna discrepancia de revisión, actualizar y entregar los archivos almacenados en caché con una estrategia CacheFirst
.
workbox.precaching.precacheAndRoute(PRECACHE);
Cómo controlar las navegaciones sin conexión
Una vez que se activa el service worker y la página sin conexión se almacena previamente en caché, se usa para responder a las solicitudes de navegación sin conexión del usuario. Si bien la app web de Mainline Menswear es una SPA, la página sin conexión solo se muestra después de que se vuelve a cargar la página, el usuario cierra y vuelve a abrir la pestaña del navegador, o bien cuando la aplicación web se inicia desde la pantalla principal sin conexión.
Para lograrlo, Mainline Menswear proporcionó un resguardo para las solicitudes de NavigationRoute
que fallaron con la página sin conexión almacenada en caché:
const htmlHandler = new workbox.strategies.NetworkOnly();
const navigationRoute = new workbox.routing.NavigationRoute(({ event }) => {
const request = event.request;
// A NavigationRoute matches navigation requests in the browser, i.e. requests for HTML
return htmlHandler.handle({ event, request }).catch(() => caches.match(OFFLINE_HTML, {
ignoreSearch: true
}));
});
workbox.routing.registerRoute(navigationRoute);
Demostración
Cómo informar instalaciones correctas
Además del seguimiento del inicio en la pantalla principal (con "start_url": "/?utm_source=pwa"
en el manifiesto de la aplicación web), la app web también informa las instalaciones de apps correctas escuchando el evento appinstalled
en window
:
window.addEventListener('appinstalled', (evt) => {
ga('send', 'event', 'Install', 'Success');
});
Si agregas capacidades de AWP a tu sitio web, mejorarás aún más la experiencia de compra de tus clientes y podrás lanzarla al mercado más rápido que una app [específica de la plataforma].
Andy Hoyle, director de Desarrollo
Conclusión
Para obtener más información sobre las apps web progresivas y cómo crearlas, visita la sección de apps web progresivas en web.dev.
Para leer más casos de éxito de apps web progresivas, navega a la sección de casos de éxito.