Mainline è un rivenditore di abbigliamento online che offre i più grandi brand di moda del settore. 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 in competizione con la 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 da integrare alla versione originale ottimizzata per il mobile del sito web Mainline Menswear, quindi confrontare le statistiche con l'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 durante la conversione del sito web in una PWA era assicurarsi che il framework scelto per il sito web (Nuxt.js, utilizzando Vue.js) fosse a prova di futuro e consentisse di sfruttare la tecnologia web in rapida evoluzione.
Risultati
139%
Più pagine per sessione nella PWA rispetto al web.
Il 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
Il 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 service worker, Mainline Menswear ha aggiunto una configurazione tramite un'implementazione
personalizzata del modulo Workbox di nuxt/pwa
.
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.
Struttura 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
interrompa. A questo scopo, devi aggiungere 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 di cache HTTP e API Cache per la memorizzazione nella cache degli asset sul 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ò sembri complicato e difficile da configurare e gestire, Workbox offre un modo semplice per dichiarare strategie così complesse e agevola 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 Nuxt CSS e JS, aumentando notevolmente le prestazioni 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 per la 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 nel foglio di stile 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 pagine sono ricche di immagini, quindi sono consapevoli
di non occupare troppo spazio sul dispositivo degli utenti. Quindi, tramite Workbox, ha aggiunto una strategia che prevede la memorizzazione nella cache delle immagini provenienti solo dalla propria CDN con un massimo di 60 immagini utilizzando ExpirationPlugin
.
La 61a immagine (la più recente) richiesta sostituisce la 1a immagine (la più vecchia), in modo che in un determinato momento non vengano memorizzate nella cache più di 60 immagini prodotto.
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 per le immagini gestisce il resto delle 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 di eventuali mancate corrispondenze 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 precaricata la pagina offline, quest'ultimo viene utilizzato 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 andate a buon fine 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
Report sulle installazioni riuscite
Oltre al monitoraggio del lancio dalla 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.