Xây dựng trải nghiệm tìm kiếm linh hoạt với Workbox

Demián Renzulli
Demián Renzulli

Lớp học lập trình này hướng dẫn bạn cách triển khai trải nghiệm tìm kiếm linh hoạt bằng Workbox. Ứng dụng minh hoạ mà ứng dụng này sử dụng có một hộp tìm kiếm gọi một điểm cuối của máy chủ và chuyển hướng người dùng đến một trang HTML cơ bản.

Đo lường

Trước khi thêm các hoạt động tối ưu hoá, bạn nên phân tích trạng thái hiện tại của ứng dụng.

  • Nhấp vào Trộn để chỉnh sửa để có thể chỉnh sửa dự án.
  • Để xem trước trang web, hãy nhấn vào Xem ứng dụng, rồi nhấn vào Toàn màn hình toàn màn hình.

Trong thẻ mới vừa mở, hãy kiểm tra cách trang web hoạt động khi chuyển sang chế độ ngoại tuyến:

  1. Nhấn tổ hợp phím `Control+Shift+J` (hoặc `Command+Option+J` trên máy Mac) để mở DevTools.
  2. Nhấp vào thẻ Mạng.
  3. Mở Công cụ của Chrome cho nhà phát triển rồi chọn bảng điều khiển Mạng.
  4. Trong danh sách thả xuống Điều tiết, hãy chọn Khi không có mạng.
  5. Trong ứng dụng minh hoạ, hãy nhập một cụm từ tìm kiếm rồi nhấp vào nút Tìm kiếm.

Trang lỗi tiêu chuẩn của trình duyệt sẽ xuất hiện:

Ảnh chụp màn hình về trải nghiệm người dùng ngoại tuyến mặc định trong trình duyệt.

Cung cấp câu trả lời dự phòng

Trình chạy dịch vụ chứa mã để thêm trang ngoại tuyến vào danh sách lưu trước vào bộ nhớ đệm, do đó, trang này luôn có thể được lưu vào bộ nhớ đệm tại sự kiện install của trình chạy dịch vụ.

Thông thường, bạn sẽ cần hướng dẫn Workbox thêm tệp này vào danh sách lưu vào bộ nhớ đệm trước tại thời điểm tạo, bằng cách tích hợp thư viện với công cụ tạo mà bạn chọn (ví dụ: webpack hoặc gulp).

Để đơn giản hoá, chúng tôi đã thực hiện việc này cho bạn. Đoạn mã sau đây tại public/sw.js sẽ thực hiện việc đó:

const FALLBACK_HTML_URL = '/index_offline.html';

workbox.precaching.precacheAndRoute([FALLBACK_HTML_URL]);

Tiếp theo, hãy thêm mã để sử dụng trang ngoại tuyến làm phản hồi dự phòng:

  1. Để xem nguồn, hãy nhấn vào Xem nguồn.
  2. Thêm mã sau vào cuối 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();
  }
});

Mã này sẽ thực hiện những việc sau:

  • Xác định một chiến lược Chỉ mạng mặc định sẽ áp dụng cho tất cả các yêu cầu.
  • Khai báo một trình xử lý lỗi chung bằng cách gọi workbox.routing.setCatchHandler() để quản lý các yêu cầu không thành công. Khi yêu cầu là dành cho tài liệu, một trang HTML dự phòng ở chế độ ngoại tuyến sẽ được trả về.

Cách kiểm thử chức năng này:

  1. Quay lại thẻ khác đang chạy ứng dụng của bạn.
  2. Đặt danh sách thả xuống Throttling (Điều tiết) về Online (Trực tuyến).
  3. Nhấn nút Quay lại của Chrome để quay lại trang tìm kiếm.
  4. Đảm bảo rằng bạn đã tắt hộp đánh dấu Tắt bộ nhớ đệm trong Công cụ cho nhà phát triển.
  5. Nhấn và giữ nút Tải lại của Chrome rồi chọn Xoá bộ nhớ đệm và tải lại hoàn toàn để đảm bảo rằng service worker của bạn đã được cập nhật.
  6. Đặt danh sách thả xuống Throttling (Điều tiết) về Offline (Ngoại tuyến) một lần nữa.
  7. Nhập cụm từ tìm kiếm rồi nhấp lại vào nút Tìm kiếm.

Trang HTML dự phòng sẽ xuất hiện:

Ảnh chụp màn hình về trải nghiệm người dùng tuỳ chỉnh khi không có mạng trong trình duyệt.

Yêu cầu cấp quyền gửi thông báo

Để đơn giản, trang ngoại tuyến tại views/index_offline.html đã chứa mã để yêu cầu quyền thông báo trong một khối tập lệnh ở dưới cùng:

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

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

Mã này sẽ thực hiện những việc sau:

  • Khi người dùng nhấp vào subscribe to notifications (đăng ký nhận thông báo), hàm requestNotificationPermission() sẽ được gọi, hàm này gọi Notification.requestPermission() để hiện lời nhắc cấp quyền mặc định của trình duyệt. Lệnh hứa sẽ phân giải bằng quyền mà người dùng chọn, có thể là granted, denied hoặc default.
  • Truyền quyền đã phân giải đến showOfflineText() để hiển thị văn bản phù hợp cho người dùng.

Lưu trữ các truy vấn ngoại tuyến và thử lại khi có kết nối mạng

Tiếp theo, hãy triển khai Workbox Background Sync để duy trì các truy vấn ngoại tuyến, nhờ đó, các truy vấn này có thể được thử lại khi trình duyệt phát hiện thấy kết nối đã được khôi phục.

  1. Mở public/sw.js để chỉnh sửa.
  2. Thêm đoạn mã sau vào cuối tệp:
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;
      }
    }
  },
});

Mã này sẽ thực hiện những việc sau:

  • workbox.backgroundSync.Plugin chứa logic để thêm các yêu cầu không thành công vào một hàng đợi để có thể thử lại sau. Các yêu cầu này sẽ được duy trì trong IndexedDB.
  • maxRetentionTime cho biết khoảng thời gian có thể thử lại một yêu cầu. Trong trường hợp này, chúng ta đã chọn 60 phút (sau đó, dữ liệu sẽ bị loại bỏ).
  • onSync là phần quan trọng nhất của mã này. Lệnh gọi lại này sẽ được gọi khi có kết nối trở lại để các yêu cầu trong hàng đợi được truy xuất rồi tìm nạp từ mạng.
  • Phản hồi mạng được thêm vào bộ nhớ đệm offline-search-responses, nối thêm tham số truy vấn &notification=true, để mục nhập bộ nhớ đệm này có thể được chọn khi người dùng nhấp vào thông báo.

Để tích hợp tính năng đồng bộ hoá trong nền với dịch vụ của bạn, hãy xác định chiến lược NetworkOnly cho các yêu cầu đến URL tìm kiếm (/search_action) và truyền bgSyncPlugin đã xác định trước đó. Thêm mã sau vào cuối 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],
  }),
);

Điều này cho biết Workbox luôn truy cập vào mạng và khi các yêu cầu không thành công, hãy sử dụng logic đồng bộ hoá trong nền.

Tiếp theo, hãy thêm mã sau vào cuối public/sw.js để xác định chiến lược lưu vào bộ nhớ đệm cho các yêu cầu đến từ thông báo. Sử dụng chiến lược CacheFirst để các tệp có thể được phân phát từ bộ nhớ đệm.

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',
  })
);

Cuối cùng, hãy thêm mã để hiển thị thông báo:

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)
  );
});

Thử nghiệm tính năng

  1. Quay lại thẻ khác đang chạy ứng dụng của bạn.
  2. Đặt danh sách thả xuống Throttling (Điều tiết) về Online (Trực tuyến).
  3. Nhấn nút Quay lại của Chrome để quay lại trang tìm kiếm.
  4. Nhấn và giữ nút Tải lại của Chrome rồi chọn Xoá bộ nhớ đệm và tải lại hoàn toàn để đảm bảo rằng service worker của bạn đã được cập nhật.
  5. Đặt danh sách thả xuống Throttling (Điều tiết) về Offline (Ngoại tuyến) một lần nữa.
  6. Nhập cụm từ tìm kiếm rồi nhấp lại vào nút Tìm kiếm.
  7. Nhấp vào đăng ký nhận thông báo.
  8. Khi Chrome hỏi bạn có muốn cấp cho ứng dụng quyền gửi thông báo hay không, hãy nhấp vào Cho phép.
  9. Nhập một cụm từ tìm kiếm khác rồi nhấp lại vào nút Tìm kiếm.
  10. Đặt danh sách thả xuống Throttling (Điều tiết) về Online (Trực tuyến) một lần nữa.

Sau khi kết nối lại, một thông báo sẽ xuất hiện:

Ảnh chụp màn hình toàn bộ quy trình ngoại tuyến.

Kết luận

Workbox cung cấp nhiều tính năng tích hợp sẵn để giúp PWA của bạn có khả năng phục hồi và hấp dẫn hơn. Trong lớp học lập trình này, bạn đã khám phá cách triển khai Background Sync API thông qua lớp trừu tượng Workbox để đảm bảo rằng các truy vấn của người dùng khi không có mạng sẽ không bị mất và có thể thử lại khi có kết nối. Bản minh hoạ này là một ứng dụng tìm kiếm đơn giản, nhưng bạn có thể sử dụng một phương thức triển khai tương tự cho các tình huống và trường hợp sử dụng phức tạp hơn, bao gồm cả ứng dụng trò chuyện, đăng tin nhắn trên mạng xã hội, v.v.