สร้างประสบการณ์การค้นหาที่ยืดหยุ่นด้วย 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 เพื่อให้แน่ใจว่าคําค้นหาของผู้ใช้แบบออฟไลน์จะไม่สูญหายและสามารถลองอีกครั้งเมื่อการเชื่อมต่อกลับมาใช้งานได้ การสาธิตเป็นแอปการค้นหาง่ายๆ แต่คุณใช้การติดตั้งใช้งานที่คล้ายกันกับสถานการณ์และกรณีการใช้งานที่ซับซ้อนมากขึ้นได้ ซึ่งรวมถึงแอปรับแชท โพสต์ข้อความในโซเชียลเน็ตเวิร์ก ฯลฯ