สร้างประสบการณ์การค้นหาที่ยืดหยุ่นด้วย Workbox

โค้ดแล็บนี้แสดงวิธีใช้ประสบการณ์การค้นหาที่ยืดหยุ่นด้วย Workbox แอปเดโมที่แอปใช้มีช่องค้นหาที่เรียกใช้ปลายทางเซิร์ฟเวอร์ และเปลี่ยนเส้นทางผู้ใช้ไปยังหน้า HTML พื้นฐาน

วัดระยะทาง

ก่อนเพิ่มการเพิ่มประสิทธิภาพ คุณควรวิเคราะห์สถานะปัจจุบันของแอปพลิเคชันก่อน

  • คลิกรีมิกซ์เพื่อแก้ไขเพื่อทำให้โปรเจ็กต์แก้ไขได้
  • หากต้องการดูตัวอย่างเว็บไซต์ ให้กดดูแอป แล้วกด เต็มหน้าจอ เต็มหน้าจอ

ในแท็บใหม่ที่เพิ่งเปิดขึ้น ให้ตรวจสอบลักษณะการทำงานของเว็บไซต์เมื่อออฟไลน์ ดังนี้

  1. กดแป้น Control+Shift+J (หรือ Command+Option+J ใน Mac) เพื่อเปิดเครื่องมือสำหรับนักพัฒนาซอฟต์แวร์
  2. คลิกแท็บเครือข่าย
  3. เปิดเครื่องมือสำหรับนักพัฒนาเว็บใน Chrome แล้วเลือกแผงเครือข่าย
  4. ในรายการแบบเลื่อนลงของการควบคุมปริมาณ ให้เลือกออฟไลน์
  5. ในแอปเดโม ให้ป้อนคำค้นหาแล้วคลิกปุ่มค้นหา

หน้าข้อผิดพลาดมาตรฐานของเบราว์เซอร์จะแสดงขึ้น

ภาพหน้าจอของ UX เริ่มต้นแบบออฟไลน์ในเบราว์เซอร์

ระบุคำตอบสำรอง

Service Worker มีโค้ดสำหรับเพิ่มหน้าออฟไลน์ลงในรายการแคชล่วงหน้า เพื่อให้แคชหน้าดังกล่าวได้เสมอที่เหตุการณ์ install ของ Service Worker

โดยปกติแล้ว คุณจะต้องสั่งให้ Workbox เพิ่มไฟล์นี้ลงในรายการแคชล่วงหน้าเมื่อถึงเวลาบิลด์ โดยผสานรวมไลบรารีกับเครื่องมือบิลด์ที่เลือก (เช่น webpack หรือ gulp)

เราได้ดำเนินการให้คุณแล้วเพื่อความสะดวก โค้ดต่อไปนี้ที่ public/sw.js จะทำสิ่งนั้น

const FALLBACK_HTML_URL = '/index_offline.html';

workbox.precaching.precacheAndRoute([FALLBACK_HTML_URL]);

ถัดไป ให้เพิ่มโค้ดเพื่อใช้หน้าออฟไลน์เป็นการตอบกลับสำรอง ดังนี้

  1. หากต้องการดูแหล่งที่มา ให้กดดูแหล่งที่มา
  2. เพิ่มโค้ดต่อไปนี้ที่ด้านล่างของ public/sw.js
workbox.routing.setDefaultHandler(new workbox.strategies.NetworkOnly());

workbox.routing.setCatchHandler(({event}) => {
  switch (event.request.destination) {
    case 'document':
      return caches.match(FALLBACK_HTML_URL);
      break;
    default:
      return Response.error();
  }
});

โค้ดจะทําสิ่งต่อไปนี้

  • กําหนดกลยุทธ์เครือข่ายเท่านั้นเริ่มต้นที่จะมีผลกับคําขอทั้งหมด
  • ประกาศตัวแฮนเดิลข้อผิดพลาดส่วนกลางโดยการเรียก workbox.routing.setCatchHandler() เพื่อจัดการคําขอที่ไม่สําเร็จ เมื่อเป็นคำขอสำหรับเอกสาร ระบบจะแสดงหน้า HTML ออฟไลน์สำรอง

วิธีทดสอบฟังก์ชันการทำงานนี้

  1. กลับไปยังแท็บอื่นที่กำลังใช้งานแอปของคุณ
  2. ตั้งค่ารายการแบบเลื่อนลงการควบคุมปริมาณกลับไปเป็นออนไลน์
  3. กดปุ่มย้อนกลับของ Chrome เพื่อกลับไปที่หน้าค้นหา
  4. ตรวจสอบว่าช่องทําเครื่องหมายปิดใช้แคชในเครื่องมือสําหรับนักพัฒนาเว็บปิดอยู่
  5. กดปุ่มโหลดซ้ำของ Chrome ค้างไว้ แล้วเลือกล้างแคชและโหลดซ้ำเพื่อให้แน่ใจว่ามีการอัปเดต Service Worker แล้ว
  6. ตั้งค่ารายการแบบเลื่อนลงการจำกัดกลับไปเป็นออฟไลน์อีกครั้ง
  7. ป้อนข้อความค้นหา แล้วคลิกปุ่มค้นหาอีกครั้ง

หน้า HTML สำรองจะแสดงดังนี้

ภาพหน้าจอของ UX ออฟไลน์ที่กำหนดเองในเบราว์เซอร์

ขอสิทธิ์การแจ้งเตือน

หน้าออฟไลน์ที่ views/index_offline.html มีโค้ดเพื่อขอสิทธิ์การแจ้งเตือนในบล็อกสคริปต์ที่ด้านล่างอยู่แล้วเพื่อความสะดวก

function requestNotificationPermission(event) {
  event.preventDefault();

  Notification.requestPermission().then(function (result) {
    showOfflineText(result);
  });
}

โค้ดจะทําสิ่งต่อไปนี้

  • เมื่อผู้ใช้คลิกสมัครรับการแจ้งเตือน ระบบจะเรียกใช้ฟังก์ชัน requestNotificationPermission() ซึ่งจะเรียกใช้ Notification.requestPermission() เพื่อแสดงข้อความแจ้งสิทธิ์ของเบราว์เซอร์เริ่มต้น Promise จะแก้ไขด้วยสิทธิ์ที่ผู้ใช้เลือก ซึ่งอาจเป็น granted, denied หรือ default
  • ส่งต่อสิทธิ์ที่แก้ไขแล้วให้กับ showOfflineText() เพื่อแสดงข้อความที่เหมาะสมแก่ผู้ใช้

เก็บการค้นหาแบบออฟไลน์ไว้และลองอีกครั้งเมื่อกลับมาออนไลน์

ถัดไป ให้ใช้การซิงค์พื้นหลังของ Workbox เพื่อเก็บการค้นหาแบบออฟไลน์ไว้ เพื่อที่จะสามารถลองอีกครั้งเมื่อเบราว์เซอร์ตรวจพบว่าการเชื่อมต่อกลับมาแล้ว

  1. เปิด public/sw.js เพื่อแก้ไข
  2. เพิ่มโค้ดต่อไปนี้ที่ส่วนท้ายของไฟล์
const bgSyncPlugin = new workbox.backgroundSync.Plugin('offlineQueryQueue', {
  maxRetentionTime: 60,
  onSync: async ({queue}) => {
    let entry;
    while ((entry = await queue.shiftRequest())) {
      try {
        const response = await fetch(entry.request);
        const cache = await caches.open('offline-search-responses');
        const offlineUrl = `${entry.request.url}&notification=true`;
        cache.put(offlineUrl, response);
        showNotification(offlineUrl);
      } catch (error) {
        await this.unshiftRequest(entry);
        throw error;
      }
    }
  },
});

โค้ดจะทําสิ่งต่อไปนี้

  • workbox.backgroundSync.Plugin มีตรรกะในการเพิ่มคำขอที่ไม่สำเร็จลงในคิวเพื่อให้ลองอีกครั้งในภายหลังได้ คำขอเหล่านี้จะคงอยู่ใน IndexedDB
  • maxRetentionTime ระบุระยะเวลาที่จะส่งคำขออีกครั้ง ในกรณีนี้ เราเลือก 60 นาที (หลังจากนั้นระบบจะทิ้งข้อมูล)
  • onSync คือส่วนที่สำคัญที่สุดของโค้ดนี้ ระบบจะเรียกใช้ Callback นี้เมื่อการเชื่อมต่อกลับมาอีกครั้งเพื่อดึงข้อมูลคำขอที่อยู่ในคิวแล้วดึงข้อมูลจากเครือข่าย
  • ระบบจะเพิ่มการตอบกลับของเครือข่ายลงในแคช offline-search-responses โดยต่อท้ายพารามิเตอร์การค้นหา &notification=true เพื่อให้ระบบดึงข้อมูลรายการแคชนี้เมื่อผู้ใช้คลิกการแจ้งเตือน

หากต้องการผสานรวมการซิงค์เบื้องหลังกับบริการ ให้กำหนดกลยุทธ์ NetworkOnly สําหรับคําขอไปยัง URL ค้นหา (/search_action) และส่ง bgSyncPlugin ที่กําหนดไว้ก่อนหน้านี้ เพิ่มโค้ดต่อไปนี้ที่ด้านล่างของ public/sw.js

const matchSearchUrl = ({url}) => {
  const notificationParam = url.searchParams.get('notification');
  return url.pathname === '/search_action' && !(notificationParam === 'true');
};

workbox.routing.registerRoute(
  matchSearchUrl,
  new workbox.strategies.NetworkOnly({
    plugins: [bgSyncPlugin],
  }),
);

การดำเนินการนี้จะบอกให้ Workbox ไปที่เครือข่ายเสมอ และเมื่อคำขอล้มเหลว ให้ใช้ตรรกะการซิงค์เบื้องหลัง

ถัดไป ให้เพิ่มโค้ดต่อไปนี้ที่ด้านล่างของ public/sw.js เพื่อกำหนดกลยุทธ์การแคชสำหรับคำขอที่มาจากข้อความแจ้ง ใช้กลยุทธ์ CacheFirst เพื่อให้ระบบแสดงเนื้อหาจากแคชได้

const matchNotificationUrl = ({url}) => {
  const notificationParam = url.searchParams.get('notification');
  return (url.pathname === '/search_action' && (notificationParam === 'true'));
};

workbox.routing.registerRoute(matchNotificationUrl,
  new workbox.strategies.CacheFirst({
     cacheName: 'offline-search-responses',
  })
);

สุดท้าย ให้เพิ่มโค้ดเพื่อแสดงการแจ้งเตือน

function showNotification(notificationUrl) {
  if (Notification.permission) {
     self.registration.showNotification('Your search is ready!', {
        body: 'Click to see you search result',
        icon: '/img/workbox.jpg',
        data: {
           url: notificationUrl
        }
     });
  }
}

self.addEventListener('notificationclick', function(event) {
  event.notification.close();
  event.waitUntil(
     clients.openWindow(event.notification.data.url)
  );
});

ทดสอบฟีเจอร์

  1. กลับไปยังแท็บอื่นที่กำลังใช้งานแอปของคุณ
  2. ตั้งค่ารายการแบบเลื่อนลงการควบคุมปริมาณกลับไปเป็นออนไลน์
  3. กดปุ่มย้อนกลับของ Chrome เพื่อกลับไปที่หน้าค้นหา
  4. กดปุ่มโหลดซ้ำของ Chrome ค้างไว้ แล้วเลือกล้างแคชและโหลดซ้ำเพื่อให้แน่ใจว่ามีการอัปเดต Service Worker แล้ว
  5. ตั้งค่ารายการแบบเลื่อนลงการจำกัดกลับไปเป็นออฟไลน์อีกครั้ง
  6. ป้อนข้อความค้นหา แล้วคลิกปุ่มค้นหาอีกครั้ง
  7. คลิกสมัครรับการแจ้งเตือน
  8. เมื่อ Chrome ถามว่าคุณต้องการให้สิทธิ์แอปส่งการแจ้งเตือนหรือไม่ ให้คลิกอนุญาต
  9. ป้อนคำค้นหาอื่นแล้วคลิกปุ่มค้นหาอีกครั้ง
  10. ตั้งค่ารายการแบบเลื่อนลงการจำกัดกลับไปเป็นออนไลน์อีกครั้ง

เมื่อการเชื่อมต่อกลับมาแล้ว ระบบจะแสดงการแจ้งเตือนดังนี้

ภาพหน้าจอของขั้นตอนออฟไลน์ทั้งหมด

บทสรุป

Workbox มีฟีเจอร์ในตัวมากมายที่จะช่วยให้ PWA มีความยืดหยุ่นและน่าสนใจมากขึ้น ในโค้ดแล็บนี้ คุณได้สำรวจวิธีใช้ Background Sync API ผ่าน Workbox Abstraction เพื่อให้แน่ใจว่าคําค้นหาของผู้ใช้แบบออฟไลน์จะไม่สูญหายและสามารถลองอีกครั้งเมื่อการเชื่อมต่อกลับมาใช้งานได้ การสาธิตเป็นแอปค้นหาง่ายๆ แต่คุณใช้การติดตั้งใช้งานที่คล้ายกันกับสถานการณ์และกรณีการใช้งานที่ซับซ้อนมากขึ้นได้ ซึ่งรวมถึงแอปรับแชท โพสต์ข้อความในโซเชียลเน็ตเวิร์ก ฯลฯ