Mainline Menswear implementa l'PWA e registra un aumento del 55% del tasso di conversione

Mainline è un rivenditore di abbigliamento online che offre i più grandi brand di stilisti della moda. L'azienda con sede nel Regno Unito si affida al suo team di esperti interni, combinato strategicamente con partner chiave, per offrire un'esperienza di acquisto senza problemi a tutti. Con una presenza sul mercato in oltre 100 paesi tramite sette siti web territoriali personalizzati e un'app, Mainline continuerà a garantire che l'offerta di e-commerce sia alla pari della concorrenza.

Sfida

L'obiettivo di Mainline Menswear era integrare l'attuale sito web ottimizzato per il mobile con funzionalità progressive che rispettino la visione "mobile first", concentrandosi su design e funzionalità ottimizzati per il mobile, tenendo presente il mercato in crescita degli smartphone.

Soluzione

L'obiettivo era creare e lanciare una PWA che integrasse la versione ottimizzata per il mobile del sito web di Mainline Menswear e poi confrontare le statistiche con la propria app mobile ibrida, attualmente disponibile su Android e iOS.

Una volta lanciata l'app e utilizzata da una piccola sezione di utenti di Mainline Menswear, è stato possibile determinare la differenza nelle statistiche chiave tra PWA, app e web.

L'approccio adottato da Mainline per convertire il proprio sito web in una PWA è stato quello di assicurarsi che il framework selezionato per il sito web (Nuxt.js, che utilizza Vue.js) fosse adatto al futuro e potesse sfruttare le tecnologie web in rapida evoluzione.

Risultati

139%

Più pagine per sessione nella PWA rispetto al web.

161%

Durata delle sessioni più lunga nelle PWA rispetto al web.

10%

Frequenza di rimbalzo inferiore nelle PWA rispetto al web

12,5%

Valore medio dell'ordine più alto nella PWA rispetto al web

55%

Tasso di conversione più elevato nella PWA rispetto al web.

243%

Entrate per sessione più elevate nelle PWA rispetto al web.

Approfondimento tecnico

Mainline Menswear utilizza il framework Nuxt.js per eseguire il bundling e il rendering del proprio sito, che è un'applicazione singola pagina (SPA).

Generazione di un file di worker di servizio

Per generare il servizio worker, Mainline Menswear ha aggiunto la configurazione tramite un'implementazione personalizzata del nuxt/pwa modulo Workbox.

Il motivo per cui è stato creato il fork del modulo nuxt/pwa è stato consentire al team di aggiungere altre personalizzazioni al file del servizio worker che non era in grado di eseguire o con cui aveva problemi quando utilizzava la versione standard. Una di queste ottimizzazioni riguardava la funzionalità offline del sito, ad esempio la pubblicazione di una pagina offline predefinita e la raccolta di dati e analisi offline.

Anatomia del file manifest dell'app web

Il team ha generato un manifest con icone per diverse dimensioni delle icone delle app mobile e altri dettagli delle app web come name, description e 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 volta installata, l'app web può essere avviata dalla schermata Home senza che il browser interferisca. Questo viene ottenuto aggiungendo il parametro display nel file manifest dell'app web:

{
  "display": "standalone"
}

Ultimo, ma non meno importante, l'azienda ora è in grado di monitorare facilmente il numero di utenti che visitano la sua app web dalla schermata Home semplicemente aggiungendo un parametro utm_source nel campo start_url del manifest:

{
  "start_url": "/?utm_source=pwa"
}

Memorizzazione nella cache di runtime per navigazioni più rapide

La memorizzazione nella cache per le app web è un must per l'ottimizzazione della velocità delle pagine e per offrire un'esperienza utente migliore agli utenti di ritorno.

Esistono diversi approcci per la memorizzazione nella cache sul web. Il team utilizza una combinazione della cache HTTP e dell'API Cache per memorizzare nella cache le risorse lato client.

L'API Cache offre a Mainline Menswear un controllo più granulare sugli asset memorizzati nella cache, consentendo di applicare strategie complesse a ogni tipo di file. Sebbene tutto ciò possa sembrare complicato e difficile da configurare e manutenere, Workbox offre un modo semplice per dichiarare strategie così complesse e semplifica la manutenzione.

Memorizzazione nella cache di CSS e JS

Per i file CSS e JS, il team ha scelto di memorizzarli nella cache e di servirli tramite la cache utilizzando la strategia Workbox StaleWhileRevalidate. Questa strategia consente di pubblicare rapidamente tutti i file CSS e JS di Nuxt, aumentando notevolmente il rendimento del sito. Allo stesso tempo, i file vengono aggiornati in background all'ultima versione per la visita successiva:

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

Memorizzazione nella cache dei caratteri Google

La strategia di memorizzazione nella cache di Google Fonts dipende da due tipi di file:

  • Il foglio di stile che contiene le dichiarazioni @font-face.
  • I file dei caratteri sottostanti (richiesti all'interno dello stile CSS sopra indicato).
// 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',
);

Memorizzazione nella cache delle immagini

Per le immagini, Mainline Menswear ha deciso di adottare due strategie. La prima strategia si applica a tutte le immagini provenienti dalla CDN, che in genere sono immagini dei prodotti. Le sue pagine contengono molte immagini, quindi deve fare attenzione a non occupare troppo spazio di archiviazione sui dispositivi degli utenti. Pertanto, tramite Workbox, hanno aggiunto una strategia che memorizza nella cache le immagini provenienti solo dalla loro CDN con un massimo di 60 immagini utilizzando ExpirationPlugin.

L'immagine 61 (la più recente) richiesta sostituisce la prima (la più vecchia) in modo che non vengano memorizzate in cache più di 60 immagini prodotto in un determinato 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 seconda strategia di immagine gestisce le altre immagini richieste dall'origine. Queste immagini tendono ad essere molto poche e piccole nell'intera origine, ma per sicurezza, anche il numero di queste immagini memorizzate nella cache è limitato 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,
      }),
    ],
  }),
);

Fornire funzionalità offline

La pagina offline viene pre-memorizzata nella cache subito dopo l'installazione e l'attivazione del service worker. Per farlo, creano un elenco di tutte le dipendenze offline: il file HTML offline e un'icona SVG offline.

const OFFLINE_HTML = '/offline/offline.html';
const PRECACHE = [
  { url: OFFLINE_HTML, revision: '70f044fda3e9647a98f084763ae2c32a' },
  { url: '/offline/offline.svg', revision: 'efe016c546d7ba9f20aefc0afa9fc74a' },
];

L'elenco della precache viene poi inviato a Workbox, che si occupa di tutte le operazioni complesse di aggiunta degli URL alla cache, verifica della mancata corrispondenza delle revisioni, aggiornamento e pubblicazione dei file precache con una strategia CacheFirst.

workbox.precaching.precacheAndRoute(PRECACHE);

Gestione delle navigazioni offline

Una volta attivato il service worker e pre-memorizzata la pagina offline, quest'ultima viene utilizzata per rispondere alle richieste di navigazione offline dell'utente. Sebbene l'app web di Mainline Menswear sia un'app SPA, la pagina offline viene visualizzata solo dopo il ricaricamento della pagina, quando l'utente chiude e riapre la scheda del browser o quando l'app web viene avviata dalla schermata Home in modalità offline.

Per raggiungere questo obiettivo, Mainline Menswear ha fornito un piano di riserva per le richieste NavigationRoute non riuscite con la pagina offline memorizzata nella cache:

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);

Demo

Esempio di pagina offline visibile su www.mainlinemenswear.co.uk.

Report sulle installazioni riuscite

Oltre al monitoraggio del lancio nella schermata Home (con "start_url": "/?utm_source=pwa" nel manifest dell'app web), l'app web registra anche le installazioni di app riuscite ascoltando l'evento appinstalled su window:

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

L'aggiunta di funzionalità PWA al tuo sito web migliorerà ulteriormente l'esperienza di acquisto dei tuoi clienti e sarà più rapida rispetto a un'app [specifica per la piattaforma].

Andy Hoyle, Head of Development

Conclusione

Per scoprire di più sulle app web progressive e su come crearle, consulta la sezione App web progressive su web.dev.

Per leggere altri case study sulle app web progressive, vai alla sezione dei case study.