Mainline เป็นผู้ค้าปลีกเสื้อผ้าออนไลน์ที่จำหน่ายแบรนด์ดีไซเนอร์ชื่อดังในวงการแฟชั่น บริษัทในสหราชอาณาจักรไว้วางใจให้ทีมผู้เชี่ยวชาญภายในทำงานร่วมกันอย่างมีกลยุทธ์กับพาร์ทเนอร์ที่สำคัญ เพื่อมอบประสบการณ์การช็อปปิ้งที่ราบรื่นให้แก่ทุกคน ด้วยการแสดงตัวตนในตลาดในกว่า 100 ประเทศผ่านเว็บไซต์และแอป 7 เขตแดนที่สร้างแบบกำหนดเอง Mainline จะยังคงดูแลให้ข้อเสนออีคอมเมิร์ซนั้นแข่งขันกับคู่แข่งได้
ชาเลนจ์
เป้าหมายของ Mainline Menswear คือการเสริมเว็บไซต์ปัจจุบันที่เพิ่มประสิทธิภาพสำหรับอุปกรณ์เคลื่อนที่ด้วยฟีเจอร์ที่ก้าวหน้าซึ่งเป็นไปตามวิสัยทัศน์ที่ "อุปกรณ์เคลื่อนที่เป็นอันดับแรก" ของบริษัท โดยมุ่งเน้นที่การออกแบบและฟังก์ชันการทำงานที่เหมาะกับอุปกรณ์เคลื่อนที่ โดยคำนึงถึงตลาดสมาร์ทโฟนที่กำลังเติบโตขึ้นเรื่อยๆ
โซลูชัน
วัตถุประสงค์คือการสร้างและเปิดตัว PWA ที่ช่วยเสริมเว็บไซต์ Mainline Menswear เวอร์ชันเดิมที่เหมาะกับอุปกรณ์เคลื่อนที่ จากนั้นเปรียบเทียบสถิติกับแอปบนอุปกรณ์เคลื่อนที่แบบผสมซึ่งขณะนี้มีให้บริการบน Android และ iOS
เมื่อเปิดตัวแอปและมีผู้ใช้งาน Mainline Menswear ไม่กี่กลุ่ม พวกเขาก็ระบุความแตกต่างของสถิติที่สำคัญระหว่าง 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
สำหรับการสร้างโปรแกรมทำงานของบริการ Mainline Menswear ได้เพิ่มการกำหนดค่าผ่านการใช้งานโมดูล Workbox ของ nuxt/pwa
แบบกำหนดเองด้วย
เหตุผลที่แยกโมดูล 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"
}
การแคชรันไทม์เพื่อให้การนำทางรวดเร็วขึ้น
การแคชเว็บแอปเป็นสิ่งจำเป็นสำหรับการเพิ่มความเร็วหน้าเว็บและช่วยให้ผู้ใช้ที่กลับมาได้รับประสบการณ์ที่ดียิ่งขึ้น
สำหรับการแคชบนเว็บนั้น มีวิธีการที่แตกต่างกันอยู่บ้าง ทีมของเราใช้แคช 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 จะขึ้นอยู่กับไฟล์ 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 ซึ่งมักเป็นรูปภาพผลิตภัณฑ์ หน้าเว็บของผู้ใช้มีรูปภาพมากเกินไป จึงระวังไม่ให้ใช้พื้นที่เก็บข้อมูลอุปกรณ์ของผู้ใช้มากเกินไป โดยทาง Workbox ได้เพิ่มกลยุทธ์ที่จะแคชรูปภาพที่มาจาก CDN ของตนเองเท่านั้นที่มีรูปภาพสูงสุด 60 ภาพโดยใช้ 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 เปิดใช้งานและหน้าออฟไลน์ถูกแคชล่วงหน้าไว้ ระบบจะใช้โปรแกรมดังกล่าวเพื่อตอบกลับคำขอการนำทางแบบออฟไลน์ของผู้ใช้ แม้ว่าเว็บแอปของ 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 ให้ไปที่ส่วนกรณีศึกษา