Mainline 是一家線上服飾零售商,販售全球知名的設計師品牌名稱。這間英國公司委託內部專家團隊與關鍵合作夥伴緊密合作,為所有人提供順暢的購物體驗。透過七個自訂地域網站和應用程式,在 100 多個國家/地區的市場曝光,Mainline 將繼續確保提供電子商務服務,讓競爭更加激烈。
挑戰
Mainline Menswear 的目標是透過符合其「行動優先」願景的漸進式功能,來補強目前針對行動裝置最佳化的網站,並將重點放在適合行動裝置的設計和功能,以及日益成長的智慧型手機市場。
解決方法
我們的目標是建構並啟動可搭配使用原始行動裝置友善版本的 Mainline Menswear 網站,然後將統計資料與目前適用於 Android 和 iOS 的混合型行動應用程式進行比較。
當 Mainline Menswear 使用者啟動應用程式並開始使用後,他們就能確定 PWA、應用程式和網頁的主要統計資料差異。
Mainline 方法在將網站轉換為 PWA 時採用的方法,是確保他們為網站選擇的架構 (透過 Vue.js 使用 Nuxt.js) 符合未來趨勢,並能利用快速移動的網路技術。
結果
139%
與網頁相比,PWA 的單次工作階段頁數更多。
161%
與網頁相比,PWA 中的工作階段持續時間較長。
10%
PWA 的跳出率降幅 (與網頁相比)
12.5%
PWA 的平均訂單價值升幅 (與網站相比)
55%
PWA 的轉換率升幅 (與網站相比)。
243%
PWA 的單次工作階段收益升幅 (與網站相比)。
深入探討技術
Mainline Menswear 使用了 Nuxt.js 架構來封裝並轉譯自家網站,也就是單頁應用程式 (SPA)。
產生 Service Worker 檔案
為了產生 Service Worker,Mainline Menswear 會透過 nuxt/pwa
Workbox 模組的自訂實作新增設定。
之所以為 nuxt/pwa
模組建立分支,是為了讓團隊為 Service Worker 檔案新增更多自訂項目,而這些自訂項目在使用 Standard 版本時不可行,或發生問題。這類最佳化措施之一與網站的「離線功能」有關,例如放送預設離線網頁及在離線時收集分析資料。
網頁應用程式資訊清單剖析
該團隊產生了資訊清單,其中包含不同的行動應用程式圖示大小,以及其他網頁應用程式詳細資料 (例如 name
、description
和 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"
}
網頁應用程式完成安裝後,就能直接從主畫面啟動,無需瀏覽器。方法是在網頁應用程式資訊清單檔案中加入 display
參數:
{
"display": "standalone"
}
最後,該公司現在可以輕鬆追蹤有多少使用者從主畫面造訪網頁應用程式,只要在資訊清單的 start_url
欄位附加 utm_source
參數即可:
{
"start_url": "/?utm_source=pwa"
}
執行階段快取,加快瀏覽速度
為了加快網頁速度,並為回訪者提供更優質的使用者體驗,網路應用程式的快取作業是不可或缺的一環。
如果您想在網路上進行快取,有幾種不同的方法。該團隊同時使用 HTTP 快取和 Cache API,以便在用戶端快取資產。
Cache API 讓 Mainline Menswear 能夠更精細地控管快取資產,因此可將複雜策略套用至每個檔案類型。儘管設定和維護看起來非常複雜且難以設定,但 Workbox 提供簡單的方式來宣告這類複雜的策略,有助於簡化維護工作。
快取 CSS 和 JS
如果是 CSS 和 JS 檔案,團隊選擇快取這些檔案,並使用 StaleWhileRevalidate
Workbox 策略,透過快取提供這些檔案。這項策略可讓他們快速提供所有 Nuxt CSS 和 JS 檔案,大幅提升網站效能。同時,檔案會在背景更新至最新版本,以便於下次造訪時使用:
/* sw.js */
workbox.routing.registerRoute(
/\/_nuxt\/.*(?:js|css)$/,
new workbox.strategies.StaleWhileRevalidate({
cacheName: 'css_js',
}),
'GET',
);
快取 Google 字型
Google Fonts 的快取策略取決於兩種檔案類型:
- 包含
@font-face
宣告的樣式表。 - 基礎字型檔案 (在上述的樣式表中要求)。
// 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',
);
快取圖片
至於圖片方面,Mainline Menswear 決定採取兩項策略。第一項策略適用於來自其 CDN (通常是產品映像檔) 的所有圖片。他們的頁面內含大量圖片,因此不易占用過多使用者的裝置儲存空間。因此,他們透過 Workbox 新增一項策略,使用 ExpirationPlugin
快取僅從 CDN 取得的圖片,最多包含 60 張圖片。
系統要求第 61 (最新) 張圖片會取代第 1 張 (最舊) 的圖片,之後在任何時間點快取的產品圖片都不超過 60 張。
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,
}),
],
}),
);
第二張圖片策略會處理來源要求的其餘圖片。這些圖片在整個來源中通常只有極少,也很少小,但為了保險起見,這些快取圖片的數量也限制為 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,
}),
],
}),
);
提供離線功能
在 Service Worker 安裝並啟用後,會立即預先快取離線網頁。方法是建立一份包含所有離線依附元件的清單:離線 HTML 檔案和離線 SVG 圖示。
const OFFLINE_HTML = '/offline/offline.html';
const PRECACHE = [
{ url: OFFLINE_HTML, revision: '70f044fda3e9647a98f084763ae2c32a' },
{ url: '/offline/offline.svg', revision: 'efe016c546d7ba9f20aefc0afa9fc74a' },
];
接著系統會將友善快取清單匯入 Workbox,該清單會負責處理將網址加入快取、檢查修訂版本是否不相符、更新,以及透過 CacheFirst
策略提供預先快取檔案的所有繁重工作。
workbox.precaching.precacheAndRoute(PRECACHE);
處理離線瀏覽
Service Worker 啟用並預先快取離線網頁後,就會使用到使用者回應的離線導航要求。雖然 Mainline Menswear 的網頁應用程式是 SPA,但離線頁面只會在重新載入頁面、使用者關閉並重新開啟瀏覽器分頁,或是從離線狀態下從主畫面啟動網頁應用程式時才會顯示。
為此,Minline Menswear 為失敗的 NavigationRoute
要求提供了備用方案,透過友善的離線網頁處理要求:
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);
操作示範
回報安裝成功
除了主畫面啟動追蹤 (在網頁應用程式資訊清單中使用 "start_url": "/?utm_source=pwa"
) 以外,網頁應用程式也會監聽 window
上的 appinstalled
事件,藉此回報應用程式安裝成功:
window.addEventListener('appinstalled', (evt) => {
ga('send', 'event', 'Install', 'Success');
});
在網站中新增 PWA 功能,可進一步改善消費者的購物體驗,且比 [平台專屬] 應用程式更快上市。
開發部門主管 Andy Hoyle
結論
如要進一步瞭解漸進式網頁應用程式及其建構方式,請前往 web.dev,參閱漸進式網頁應用程式專區。
如需更多漸進式網頁應用程式個案研究,請前往個案研究一節。