إنشاء تجارب بحث مرنة باستخدام Workbox

يوضّح لك هذا الدرس التطبيقي حول الترميز كيفية تنفيذ تجربة بحث متينة باستخدام Workbox. يحتوي التطبيق التجريبي الذي يستخدمه على مربّع بحث يستدعي نقطة نهاية خادم ويعيد توجيه المستخدم إلى صفحة HTML أساسية.

القياس

قبل إضافة أي تحسينات، من الأفضل تحليل الحالة الحالية للتطبيق أولاً.

  • انقر على Remix to Edit (إنشاء ريمكس لتعديله) ليصبح المشروع قابلاً للتعديل.
  • لمعاينة الموقع الإلكتروني، اضغط على عرض التطبيق. ثم اضغط على ملء الشاشة ملء الشاشة.

في علامة التبويب الجديدة التي تم فتحها للتو، تحقّق من سلوك الموقع الإلكتروني عند عدم الاتصال بالإنترنت:

  1. اضغط على Ctrl ‏+ Shift ‏+ J (أو Command ‏+ Option ‏+ J على نظام التشغيل Mac) لفتح DevTools.
  2. انقر على علامة التبويب الشبكة.
  3. افتح أدوات مطوري البرامج في Chrome واختَر لوحة "الشبكة".
  4. في القائمة المنسدلة "تقييد السرعة"، اختَر بلا إنترنت.
  5. في التطبيق التجريبي، أدخِل طلب بحث، ثم انقر على الزر بحث.

تظهر صفحة الخطأ العادية للمتصفّح:

لقطة شاشة لتجربة المستخدم التلقائية بلا إنترنت في المتصفّح

تقديم ردّ احتياطي

يحتوي مشغّل الخدمات على رمز لإضافة الصفحة بلا اتصال بالإنترنت إلى قائمة التخزين المؤقّت، كي يمكن تخزينها مؤقتًا في حدث عامل الخدمة install دائمًا.

عليك عادةً توجيه 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. اضبط القائمة المنسدلة Throttling (تقييد السرعة) مرة أخرى على Online (متصل بالإنترنت).
  3. اضغط على زر رجوع في Chrome للانتقال مرة أخرى إلى صفحة البحث.
  4. تأكَّد من أنّ مربّع الاختيار إيقاف ذاكرة التخزين المؤقت في "أدوات مطوّري البرامج" غير مفعّل.
  5. اضغط مع الاستمرار على زر إعادة التحميل في Chrome واختَر إفراغ ذاكرة التخزين المؤقت وإعادة التحميل من جديد لضمان تحديث الخدمة العاملة.
  6. اضبط القائمة المنسدلة تقييد السرعة مرة أخرى على بلا إنترنت.
  7. أدخِل طلب بحث، ثم انقر على الزر بحث مرة أخرى.

يتم عرض صفحة HTML الاحتياطية:

لقطة شاشة لتجربة المستخدم المخصّصة بلا إنترنت في المتصفّح

طلب إذن إرسال الإشعارات

للتبسيط، تتضمّن الصفحة المتوفّرة بلا إنترنت في views/index_offline.html الرمز الذي يتيح طلب أذونات إرسال الإشعارات في كتلة نص برمجي في أسفل الصفحة:

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

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

تؤدي التعليمة البرمجية ما يلي:

  • عندما ينقر المستخدم على الاشتراك في الإشعارات، يتمّ استدعاء الدالة requestNotificationPermission() التي تستدعي Notification.requestPermission() لعرض طلب الإذن التلقائي للمتصفّح. يتم حلّ الوعد بالإذن الذي يختاره المستخدم، والذي يمكن أن يكون 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 هو الجزء الأكثر أهمية في هذا الرمز. سيتم استدعاء دالة ردّ الاتصال هذه عند استعادة الاتصال حتى يتم استرداد الطلبات التي في "قائمة الانتظار" ثم جلبها من الشبكة.
  • تتم إضافة استجابة الشبكة إلى ذاكرة التخزين المؤقت 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. اضبط القائمة المنسدلة Throttling (تقييد السرعة) مرة أخرى على Online (متصل بالإنترنت).
  3. اضغط على زر رجوع في Chrome للانتقال مرة أخرى إلى صفحة البحث.
  4. اضغط مع الاستمرار على زر إعادة التحميل في Chrome وحدد إفراغ ذاكرة التخزين المؤقت وإعادة التحميل الثابت لضمان تحديث عامل الخدمة.
  5. أعِد ضبط القائمة المنسدلة تقييد البيانات على بلا إنترنت مرّة أخرى.
  6. أدخِل طلب بحث، ثم انقر على الزر بحث مرة أخرى.
  7. انقر على الاشتراك في الإشعارات.
  8. عندما يسألك Chrome ما إذا كنت تريد منح التطبيق الإذن بإرسال الإشعارات، انقر على سماح.
  9. أدخِل طلب بحث آخر وانقر على الزر بحث مرة أخرى.
  10. اضبط القائمة المنسدلة Throttling (تقييد السرعة) مرة أخرى على Online (متصل بالإنترنت).

بعد استعادة الاتصال، سيظهر إشعار:

لقطة شاشة للتدفق الكامل بلا اتصال بالإنترنت

الخاتمة

يوفّر Workbox العديد من الميزات المدمجة لجعل تطبيقات الويب التقدّمية أكثر مرونة وتفاعلية. في هذا الدليل التعليمي حول الرموز البرمجية، تعرّفت على كيفية تنفيذ واجهة برمجة التطبيقات Background Sync API من خلال واجهة Workbox المجردة، لضمان عدم فقدان طلبات بحث المستخدمين بلا اتصال بالإنترنت، وإمكانية إعادة المحاولة بعد استعادة الاتصال. العرض التقديمي هو تطبيق بحث بسيط، ولكن يمكنك استخدام عملية تنفيذ مشابهة لسيناريوهات وحالات استخدام أكثر تعقيدًا، بما في ذلك تطبيقات المحادثة ونشر الرسائل على شبكة اجتماعية وما إلى ذلك.