Mainline เป็นผู้ค้าปลีกเสื้อผ้าออนไลน์ที่นำเสนอแบรนด์ดีไซเนอร์ชื่อดังที่สุดในวงการแฟชั่น บริษัทในสหราชอาณาจักรมอบความไว้วางใจให้ทีมผู้เชี่ยวชาญภายในที่ผสมผสานอย่างมีกลยุทธ์กับพาร์ทเนอร์รายสำคัญเพื่อมอบประสบการณ์การช็อปปิ้งที่ราบรื่นสำหรับทุกคน Mainline ให้บริการในกว่า 100 ประเทศผ่านเว็บไซต์และแอปสำหรับเขตแดนที่สร้างขึ้นเอง 7 แห่ง Mainline จะยังคงดูแลให้ข้อเสนออีคอมเมิร์ซสามารถแข่งขันกับคู่แข่งได้
ความท้าทาย
เป้าหมายของ Mainline Menswear คือการเสริมเว็บไซต์ที่เพิ่มประสิทธิภาพสำหรับอุปกรณ์เคลื่อนที่ในปัจจุบันด้วยฟีเจอร์ที่ก้าวหน้าซึ่งสอดคล้องกับวิสัยทัศน์ของ "อุปกรณ์เคลื่อนที่เป็นอันดับแรก" โดยมุ่งเน้นการออกแบบและฟังก์ชันที่เหมาะกับอุปกรณ์เคลื่อนที่โดยคำนึงถึงตลาดสมาร์ทโฟนที่กำลังเติบโตเป็นหลัก
โซลูชัน
วัตถุประสงค์คือการสร้างและเปิดตัว PWA ที่มาเสริมเว็บไซต์ Mainline Menswear เวอร์ชันเดิมที่เหมาะกับอุปกรณ์เคลื่อนที่ แล้วเปรียบเทียบสถิติกับแอปบนอุปกรณ์เคลื่อนที่แบบไฮบริดซึ่งปัจจุบันพร้อมให้บริการบน Android และ iOS
เมื่อเปิดตัวแอปและมีผู้ใช้ส่วนบุรุษ Mainline เพียงส่วนน้อยใช้แอปดังกล่าว ทางทีมสามารถระบุความแตกต่างของสถิติสำคัญระหว่าง PWA, แอป และเว็บได้
แนวทางที่ Mainline ใช้เมื่อแปลงเว็บไซต์เป็น PWA คือการตรวจสอบว่าเฟรมเวิร์กซึ่งเลือกไว้สําหรับเว็บไซต์ (Nuxt.js ที่ใช้ Vue.js) จะใช้งานได้ในอนาคตและช่วยให้ใช้ประโยชน์จากเทคโนโลยีเว็บที่พัฒนาอย่างรวดเร็วได้
ผลลัพธ์
139%
จำนวนหน้าเว็บต่อเซสชันใน PWA มากกว่าในเว็บ
161%
ระยะเวลาเซสชันที่นานขึ้นใน PWA เทียบกับเว็บ
10%
อัตราตีกลับใน PWA ที่ต่ำกว่าเมื่อเทียบกับเว็บ
12.5%
มูลค่าการสั่งซื้อเฉลี่ยสูงกว่าใน PWA เมื่อเทียบกับเว็บ
55%
อัตรา Conversion ใน PWA สูงกว่าในเว็บ
243%
รายได้ต่อเซสชันใน PWA สูงกว่าในเว็บ
ข้อมูลทางเทคนิคแบบเจาะลึก
Mainline Menswear ใช้เฟรมเวิร์ก Nuxt.js เพื่อรวมและแสดงผลเว็บไซต์ ซึ่งเป็นแอปพลิเคชันหน้าเว็บเดียว (SPA)
การสร้างไฟล์ Service Worker
ส่วนการสร้าง Service Worker นั้น Mainline Menswear ได้เพิ่มการกำหนดค่าผ่านการใช้งานแบบกำหนดเองของโมดูล nuxt/pwa
Workbox
เหตุผลที่แยกโมดูล nuxt/pwa
ออกมาคือเพื่อให้ทีมเพิ่มการปรับแต่งเพิ่มเติมในไฟล์ Service Worker ที่ไม่สามารถทำได้หรือพบปัญหาเมื่อใช้เวอร์ชันมาตรฐาน
การเพิ่มประสิทธิภาพอย่างหนึ่งคือฟังก์ชันการทำงานแบบออฟไลน์ของเว็บไซต์ เช่น การแสดงหน้าเว็บออฟไลน์เริ่มต้นและการรวบรวมข้อมูลวิเคราะห์ขณะออฟไลน์
โครงสร้างของไฟล์ Manifest ของเว็บแอป
ทีมสร้างไฟล์ Manifest ที่มีไอคอนสำหรับขนาดไอคอนแอปบนอุปกรณ์เคลื่อนที่ขนาดต่างๆ และรายละเอียดอื่นๆ ของเว็บแอป เช่น 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
ในไฟล์ Manifest ของเว็บแอป
{
"display": "standalone"
}
สุดท้ายนี้ บริษัทสามารถติดตามจํานวนผู้ใช้ที่เข้าชมเว็บแอปจากหน้าจอหลักได้โดยง่าย เพียงเพิ่มพารามิเตอร์ utm_source
ในช่อง start_url
ของไฟล์ Manifest ดังนี้
{
"start_url": "/?utm_source=pwa"
}
การแคชรันไทม์เพื่อการไปยังส่วนต่างๆ ที่รวดเร็วยิ่งขึ้น
การแคชสําหรับเว็บแอปเป็นสิ่งที่จําเป็นต่อการเพิ่มประสิทธิภาพความเร็วหน้าเว็บและมอบประสบการณ์การใช้งานที่ดีขึ้นให้แก่ผู้ใช้ที่กลับมา
สำหรับการแคชบนเว็บ มีวิธีการที่แตกต่างกันอยู่ 2-3 วิธี ทีมดังกล่าวใช้แคช HTTP และ Cache API ร่วมกันสำหรับการแคชเนื้อหาในฝั่งไคลเอ็นต์
Cache API ช่วยให้ Mainline Menswear ควบคุมเนื้อหาที่แคชไว้ได้ละเอียดยิ่งขึ้น ซึ่งช่วยให้ใช้กลยุทธ์ที่ซับซ้อนกับไฟล์แต่ละประเภทได้ แม้ว่าฟังดูซับซ้อนและตั้งค่าและดูแลรักษาได้ยาก แต่ Workbox ช่วยให้ประกาศกลยุทธ์ที่ซับซ้อนดังกล่าวได้อย่างง่ายดายและลดความยุ่งยากในการดูแลรักษา
การแคช CSS และ JS
สําหรับไฟล์ CSS และ JS ทางทีมเลือกที่จะแคชไฟล์และแสดงผ่านแคชโดยใช้กลยุทธ์ Workbox ของ StaleWhileRevalidate
กลยุทธ์นี้ช่วยให้แสดงไฟล์ CSS และ JS ทั้งหมดของ Nuxt ได้อย่างรวดเร็ว ซึ่งช่วยเพิ่มประสิทธิภาพของเว็บไซต์ได้อย่างมาก
ในขณะเดียวกัน ระบบจะอัปเดตไฟล์ในเบื้องหลังเป็นเวอร์ชันล่าสุดสำหรับการเข้าชมครั้งถัดไป
/* sw.js */
workbox.routing.registerRoute(
/\/_nuxt\/.*(?:js|css)$/,
new workbox.strategies.StaleWhileRevalidate({
cacheName: 'css_js',
}),
'GET',
);
กำลังแคช Google Fonts
กลยุทธ์ในการแคช Google Fonts ขึ้นอยู่กับไฟล์ 2 ประเภท ได้แก่
- สไตล์ชีตที่มีการประกาศ
@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 ตัดสินใจเลือก 2 กลยุทธ์ด้วยกัน กลยุทธ์แรกใช้กับรูปภาพทั้งหมดที่มาจาก CDN ซึ่งมักจะเป็นรูปภาพผลิตภัณฑ์ หน้าเว็บมีรูปภาพจำนวนมาก จึงต้องคำนึงถึงการใช้พื้นที่เก็บข้อมูลในอุปกรณ์ของผู้ใช้ให้น้อยที่สุด ดังนั้น พวกเขาจึงเพิ่มกลยุทธ์แคชรูปภาพจาก CDN เท่านั้นโดยใช้ รูปภาพสูงสุด 60 รูปผ่าน Workbox โดยใช้ ExpirationPlugin
รูปภาพที่ 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,
}),
],
}),
);
กลยุทธ์รูปภาพลำดับที่ 2 จะจัดการรูปภาพที่เหลือที่แหล่งที่มาขอ รูปภาพเหล่านี้มีจำนวนน้อยมากและมีขนาดค่อนข้างเล็กในแหล่งที่มาทั้งหมด แต่เพื่อความไม่ประมาท ระบบจึงจำกัดจำนวนรูปภาพที่แคชไว้เหล่านี้ไว้ที่ 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 ซึ่งทำได้โดยการสร้างรายการทรัพยากร Dependency แบบออฟไลน์ทั้งหมด ได้แก่ ไฟล์ HTML ออฟไลน์และไอคอน SVG แบบออฟไลน์
const OFFLINE_HTML = '/offline/offline.html';
const PRECACHE = [
{ url: OFFLINE_HTML, revision: '70f044fda3e9647a98f084763ae2c32a' },
{ url: '/offline/offline.svg', revision: 'efe016c546d7ba9f20aefc0afa9fc74a' },
];
จากนั้นระบบจะส่งรายการที่แคชไว้ล่วงหน้าไปยัง Workbox ซึ่งจะจัดการงานหนักทั้งหมดในการเพิ่ม URL ลงในแคช ตรวจสอบการแก้ไขที่ไม่ตรงกัน อัปเดต และแสดงไฟล์ที่แคชไว้ล่วงหน้าด้วยกลยุทธ์ CacheFirst
workbox.precaching.precacheAndRoute(PRECACHE);
การจัดการการนําทางแบบออฟไลน์
เมื่อ Service Worker เปิดใช้งานและมีการแคชหน้าเว็บออฟไลน์ไว้ล่วงหน้า ระบบจะใช้ Service Worker เพื่อตอบสนองต่อคำขอการไปยังส่วนต่างๆ ของหน้าเว็บแบบออฟไลน์ของผู้ใช้ แม้ว่าเว็บแอปของ Mainline Menswear จะเป็น SPA แต่หน้าเว็บออฟไลน์จะแสดงหลังจากที่หน้าเว็บโหลดซ้ำ ผู้ใช้ปิดและเปิดแท็บเบราว์เซอร์อีกครั้ง หรือเมื่อเปิดเว็บแอปจากหน้าจอหลักขณะออฟไลน์เท่านั้น
Mainline 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"
ในไฟล์ Manifest ของแอปบนเว็บ) เว็บแอปยังรายงานการติดตั้งแอปที่สำเร็จโดยรับฟังเหตุการณ์ appinstalled
ใน window
ด้วย
window.addEventListener('appinstalled', (evt) => {
ga('send', 'event', 'Install', 'Success');
});
การเพิ่มความสามารถของ PWA ลงในเว็บไซต์จะช่วยปรับปรุงประสบการณ์การช็อปปิ้งของลูกค้าให้ดียิ่งขึ้น และคุณจะทําการตลาดได้เร็วกว่าแอป [เฉพาะแพลตฟอร์ม]
Andy Hoyle หัวหน้าฝ่ายพัฒนา
บทสรุป
ดูข้อมูลเพิ่มเติมเกี่ยวกับ Progressive Web App และวิธีสร้างได้ที่ส่วน Progressive Web App ใน web.dev
หากต้องการอ่านกรณีศึกษาเพิ่มเติมเกี่ยวกับ Progressive Web App ให้ไปที่ส่วนกรณีศึกษา