Mainline Menswear implementa AWP y logra un aumento del 55% en el porcentaje de conversiones

Mainline es un minorista de ropa en línea que ofrece los principales diseñadores de marcas de moda. Esta empresa con sede en el Reino Unido confía en su equipo de expertos internos, que se combinó de forma estratégica con socios clave para brindarles una experiencia de compra sin inconvenientes. Con 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 actual sitio web optimizado para dispositivos móviles con funciones progresivas que se adhieren a su visión de "prioridad para dispositivos móviles" y se centrara en un diseño y funcionalidad optimizados para dispositivos móviles, con un mercado de smartphones en crecimiento.

Solución

El objetivo era crear y lanzar una AWP que complementara la versión original optimizada para dispositivos móviles del sitio web Mainline Menswear y, luego, comparar las estadísticas con su app para dispositivos móviles híbrida, que actualmente está disponible en iOS y Android.

Una vez que se lanzó la app y una pequeña sección de usuarios de Mainline Menswear la usó, pudieron determinar la diferencia en las estadísticas clave entre la AWP, la app y la Web.

El enfoque que adoptó Mainline al convertir su sitio web en una AWP fue asegurarse de que el framework que seleccionaron para su sitio web (Nuxt.js, con Vue.js) estuviera preparado para el futuro y le permitiera aprovechar la tecnología web de rápida evolución.

Resultados

El 139%

Más páginas por sesión en la AWP que en la Web.

El 161%

Mayor duración de las sesiones en las AWP que en la Web.

10%

de disminución del porcentaje de rebote en las AWP que en la Web

12,5%

Mayor valor promedio del pedido en la AWP en comparación con la Web

El 55%

de aumento en el porcentaje de conversiones en las AWP que en la Web

El 243%

de aumento en los ingresos por sesión en las AWP que en la Web

Información técnica detallada

Mainline Menswear usa el framework de Nuxt.js para empaquetar y renderizar su sitio, que es una aplicación de una sola página (SPA).

Genera un archivo de service worker

Para generar el service worker, Mainline Menswear agregó la configuración a través de una implementación personalizada del módulo nuxt/pwa Workbox.

La razón por la que bifurcó el módulo nuxt/pwa fue para permitir que el equipo agregara más personalizaciones al archivo de service worker con las que no pudo o tuvo problemas cuando usaba la versión estándar. Una de esas optimizaciones tenía que ver con la funcionalidad sin conexión del sitio, como, por ejemplo, entregar 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 las 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 se interponga. Para ello, agrega el parámetro display en el archivo de manifiesto de la app web:

{
  "display": "standalone"
}

Por último, la empresa ahora puede realizar un seguimiento sencillo de la cantidad de usuarios que visitan su aplicación 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 navegar más rápido

El almacenamiento en caché de las apps web es fundamental para la optimización de la velocidad de la página y con el objetivo de proporcionar una mejor experiencia del usuario a los usuarios recurrentes.

Para almacenar en caché en la Web, existen varios enfoques diferentes. El equipo combina la caché de HTTP y la API de Cache para almacenar recursos en caché del cliente.

La API de Cache brinda a Mainline Menswear un control más preciso sobre los elementos almacenados en caché, lo que les permite aplicar estrategias complejas a cada tipo de archivo. Si bien todo esto parece complicado y difícil de configurar y mantener, Workbox les proporciona una manera fácil de declarar estrategias tan complejas y facilita las dificultades de mantenimiento.

Almacenamiento en caché de CSS y JS

Para los archivos CSS y JS, el equipo eligió almacenarlos en caché y entregarlos a través de ella con la estrategia StaleWhileRevalidate de Workbox. Esta estrategia les permite entregar todos los archivos CSS y JS Nuxt con rapidez, lo que aumenta de manera significativa el rendimiento de su sitio. Al mismo tiempo, se están actualizando los archivos en segundo plano a la última versión para la próxima visita:

/* sw.js */
workbox.routing.registerRoute(
  /\/_nuxt\/.*(?:js|css)$/,
  new workbox.strategies.StaleWhileRevalidate({
    cacheName: 'css_js',
  }),
  'GET',
);

Cómo almacenar fuentes de Google en caché

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 antes mencionada)
// 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',
);

Almacena imágenes en caché

En cuanto a 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 suelen ser imágenes de productos. Sus páginas tienen muchas imágenes, por lo que están conscientes de no ocupar demasiado espacio de almacenamiento en el dispositivo de los usuarios. Por lo tanto, a través de Workbox, agregaron una estrategia que consiste en almacenar en caché imágenes que provienen solo de su CDN con un máximo de 60 imágenes con ExpirationPlugin.

La 61.a imagen (más nueva) solicitada reemplaza la primera imagen (más antigua) para que no se almacenen en caché más de 60 imágenes de producto en cualquier 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 en todo el origen, pero por seguridad, la cantidad de 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,
      }),
    ],
  }),
);

Proporcionando funcionalidad sin conexión

La página sin conexión se almacena en caché inmediatamente 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 previo 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 discrepancias en las revisiones, actualizar y entregar los archivos prealmacenados en caché con una estrategia CacheFirst.

workbox.precaching.precacheAndRoute(PRECACHE);

Cómo administrar las navegaciones sin conexión

Una vez que se activa el service worker y se almacena previamente la página sin conexión en caché, esta se utiliza para responder a las solicitudes de navegación sin conexión del usuario. Si bien la aplicación web de Mainline Menswear es una SPA, la página sin conexión se muestra solo después de que se vuelve a cargar la página, el usuario cierra y vuelve a abrir la pestaña del navegador o cuando la aplicación web se inicia desde la pantalla principal sin conexión.

Para lograrlo, Mainline Menswear proporcionó un resguardo a las solicitudes NavigationRoute fallidas con la página sin conexión que se prealmacena 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

Ejemplo de página sin conexión como se ve en www.mainlinemenswear.co.uk.

Cómo informar instalaciones exitosas

Además del seguimiento del inicio de 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 correctas de la app escuchando el evento appinstalled en window:

window.addEventListener('appinstalled', (evt) => {
  ga('send', 'event', 'Install', 'Success');
});

Agregar funciones de AWP a tu sitio web mejorará aún más la experiencia de los clientes cuando compran en tu empresa, y será más rápido en comercializar que una app [específica para la plataforma].

Andy Hoyle, jefe de Desarrollo

Conclusión

Para obtener más información sobre las apps web progresivas y cómo compilarlas, ve a la sección de apps web progresivas en web.dev.

Para leer más casos de éxito de las apps web progresivas, navega a la sección de casos de éxito.