استخدام المكونات الإضافية

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

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

مكونات Workbox الإضافية المتاحة

يوفّر Workbox الإضافات الرسمية التالية لاستخدامها في عامل الخدمة:

  • BackgroundSyncPlugin: إذا تعذّر إرسال طلب إلى الشبكة، يسمح لك هذا المكوّن الإضافي بإضافته إلى قائمة انتظار المزامنة في الخلفية ليتم طلبه مرة أخرى عند بدء حدث المزامنة التالي.
  • BroadcastUpdatePlugin: يسمح لك بإرسال رسالة إلى قناة بث أو عبر postMessage() عند تعديل ذاكرة التخزين المؤقت.
  • CacheableResponsePlugin: طلبات ذاكرة التخزين المؤقت التي تستوفي معايير محدّدة فقط
  • ExpirationPlugin: تُستخدَم لإدارة عدد العناصر والحد الأقصى لعمرها في ذاكرة التخزين المؤقت.
  • RangeRequestsPlugin: الاستجابة للطلبات التي تتضمن عنوان طلب HTTP Range

يتم استخدام مكوّنات Workbox الإضافية، سواء كانت إحدى المكوّنات المدرَجة أعلاه أو مكوّنًا إضافيًا مخصّصًا، مع استراتيجية Workbox من خلال إضافة مثيل للمكوّن الإضافي إلى موقع plugins الخاص بالاستراتيجية:

import {registerRoute} from 'workbox-routing';
import {CacheFirst} from 'workbox-strategies';
import {ExpirationPlugin} from 'workbox-expiration';

registerRoute(
  ({request}) => request.destination === 'image',
  new CacheFirst({
    cacheName: 'images',
    plugins: [
      new ExpirationPlugin({
        maxEntries: 60,
        maxAgeSeconds: 30 * 24 * 60 * 60, // 30 Days
      }),
    ],
  })
);

طرق استخدام المكوّنات الإضافية المخصّصة

يجب أن ينفذ مكوّن Workbox الإضافي دالة ردّ اتصال واحدة أو أكثر. عند إضافة مكوّن إضافي إلى استراتيجية، يتم تشغيل وظائف الاستدعاء تلقائيًا في الوقت المناسب. تُرسِل الاستراتيجية إلى دالة الاستدعاء معلومات ذات صلة بالطلب و/أو الردّ الحاليَين، ما يمنح المكوّن الإضافي السياق الذي يحتاجه لاتخاذ إجراء. تتوفّر دوال معاودة الاتصال التالية:

  • cacheWillUpdate: يتمّ استدعاؤه قبل استخدام Response لتعديل ذاكرة التخزين المؤقت. بهذه الطريقة، يمكن تغيير الردّ قبل إضافته إلى ذاكرة التخزين المؤقت، أو يمكنك عرض null لتجنُّب تعديل ذاكرة التخزين المؤقت بالكامل.
  • cacheDidUpdate: يتم استدعاؤه عند إضافة إدخال جديد إلى ذاكرة تخزين مؤقت أو عند تعديل إدخال حالي. قد تكون الإضافات التي تستخدم هذه الطريقة مفيدة عندما تريد تنفيذ إجراء بعد تحديث ذاكرة التخزين المؤقت.
  • cacheKeyWillBeUsed: يتم استدعاؤه قبل استخدام طلب كمفتاح ذاكرة تخزين مؤقت. يحدث ذلك لكلّ من عمليات البحث في ذاكرة التخزين المؤقت (عندما يكون mode هو 'read') وعمليات الكتابة في ذاكرة التخزين المؤقت (عندما يكون mode هو 'write'). يكون هذا المرجع البرمجي مفيدًا إذا كنت بحاجة إلى إلغاء عناوين URL أو تسويتها قبل استخدامها للوصول إلى ذاكرات التخزين المؤقت.
  • cachedResponseWillBeUsed: يتمّ استدعاء هذا الإجراء قبل استخدام استجابة من ذاكرة التخزين المؤقت مباشرةً، ما يتيح لك فحص هذه الاستجابة. في هذه المرحلة، يمكنك إما عرض استجابة مختلفة أو عرض null.
  • requestWillFetch: يتم الاتصال عندما يكون هناك طلب على وشك الانتقال إلى الشبكة. يكون ذلك مفيدًا عندما تحتاج إلى تغيير Request قبل إرسالها إلى الشبكة مباشرةً.
  • fetchDidFail: يتمّ استدعاؤه عند تعذُّر طلب الشبكة، ويعود السبب على الأرجح إلى عدم توفّر اتصال بالشبكة، ولن يتمّ تشغيله عندما يكون المتصفّح متصلاً بالشبكة، ولكنّه يتلقّى خطأ (على سبيل المثال، 404 Not Found).
  • fetchDidSucceed: يتمّ استدعاؤه عند نجاح طلب من الشبكة، بغضّ النظر عن رمز استجابة HTTP.
  • handlerWillStart: يتمّ استدعاؤه قبل بدء تنفيذ أيّ منطق للمعالج، وهو مفيد إذا كنت بحاجة إلى ضبط حالة المعالج الأوّلية. على سبيل المثال، إذا أردت معرفة الوقت الذي استغرقه معالِج الطلب لإنشاء ردّ، يمكنك تدوين وقت البدء في هذه الدالة المخصّصة للردّ.
  • handlerWillRespond: يتمّ استدعاء هذه الطريقة قبل أن تعرِض طريقة handle() في الاستراتيجية استجابةً، ما يُعدّ مفيدًا إذا كنت بحاجة إلى تعديل استجابة قبل عرضها على RouteHandler أو منطق مخصّص آخر.
  • handlerDidRespond: يتمّ استدعاؤها بعد أن تُعيد طريقة handle() الاستراتيجية استجابةً. في هذه الحالة، قد يكون من المفيد تسجيل أي تفاصيل نهائية للردّ (على سبيل المثال، بعد التغييرات التي أجرتها إضافات أخرى).
  • handlerDidComplete: يتمّ استدعاؤه بعد تسوية جميع التعهدات بتمديد فترة الاشتراك التي تمت إضافتها إلى الحدث من طلب تنفيذ الاستراتيجية. يكون ذلك مفيدًا إذا كنت بحاجة إلى إعداد تقارير عن أي بيانات يجب الانتظار حتى تنتهي معالجتها من أجل احتساب أشياء مثل حالة مطابقة ذاكرة التخزين المؤقت ووقت استجابة ذاكرة التخزين المؤقت ووقت استجابة الشبكة ومعلومات مفيدة أخرى.
  • handlerDidError: يتم استدعاؤه إذا لم يتمكّن المعالج من تقديم استجابة صالحة من أي مصدر، وهو الوقت الأمثل لتقديم نوع من الردود الاحتياطية كبديل للإخفاق تمامًا.

جميع عمليات الاستدعاء هذه هي من النوع async، وبالتالي ستتطلّب استخدام await كلما وصل حدث ذاكرة التخزين المؤقت أو الجلب إلى النقطة ذات الصلة بعملية الاستدعاء المعنية.

إذا استخدم مكوّن إضافي جميع عمليات الاستدعاء المذكورة أعلاه، فستكون هذه هي التعليمة البرمجية الناتجة:

const myPlugin = {
  cacheWillUpdate: async ({request, response, event, state}) => {
    // Return `response`, a different `Response` object, or `null`.
    return response;
  },
  cacheDidUpdate: async ({
    cacheName,
    request,
    oldResponse,
    newResponse,
    event,
    state,
  }) => {
    // No return expected
    // Note: `newResponse.bodyUsed` is `true` when this is called,
    // meaning the body has already been read. If you need access to
    // the body of the fresh response, use a technique like:
    // const freshResponse = await caches.match(request, {cacheName});
  },
  cacheKeyWillBeUsed: async ({request, mode, params, event, state}) => {
    // `request` is the `Request` object that would otherwise be used as the cache key.
    // `mode` is either 'read' or 'write'.
    // Return either a string, or a `Request` whose `url` property will be used as the cache key.
    // Returning the original `request` will make this a no-op.
    return request;
  },
  cachedResponseWillBeUsed: async ({
    cacheName,
    request,
    matchOptions,
    cachedResponse,
    event,
    state,
  }) => {
    // Return `cachedResponse`, a different `Response` object, or null.
    return cachedResponse;
  },
  requestWillFetch: async ({request, event, state}) => {
    // Return `request` or a different `Request` object.
    return request;
  },
  fetchDidFail: async ({originalRequest, request, error, event, state}) => {
    // No return expected.
    // Note: `originalRequest` is the browser's request, `request` is the
    // request after being passed through plugins with
    // `requestWillFetch` callbacks, and `error` is the exception that caused
    // the underlying `fetch()` to fail.
  },
  fetchDidSucceed: async ({request, response, event, state}) => {
    // Return `response` to use the network response as-is,
    // or alternatively create and return a new `Response` object.
    return response;
  },
  handlerWillStart: async ({request, event, state}) => {
    // No return expected.
    // Can set initial handler state here.
  },
  handlerWillRespond: async ({request, response, event, state}) => {
    // Return `response` or a different `Response` object.
    return response;
  },
  handlerDidRespond: async ({request, response, event, state}) => {
    // No return expected.
    // Can record final response details here.
  },
  handlerDidComplete: async ({request, response, error, event, state}) => {
    // No return expected.
    // Can report any data here.
  },
  handlerDidError: async ({request, event, error, state}) => {
    // Return a `Response` to use as a fallback, or `null`.
    return fallbackResponse;
  },
};

عنصر event المتاح في وظائف الاستدعاء المُدرَجة أعلاه هو الحدث الأصلي الذي أدّى إلى بدء إجراء الجلب أو التخزين المؤقت. في بعض الأحيان، لن يكون هناك حدث أصلي، لذا يجب أن يتحقّق الرمز من توفّره قبل الإشارة إليه.

يتم أيضًا تمرير عنصر state إلى جميع عمليات الاستدعاء الخاصة بالمكونات الإضافية، وهو عنصر فريد لإضافة معيّنة والاستراتيجية التي تستدعيها. وهذا يعني أنّه يمكنك كتابة مكوّنات إضافية يمكن فيها لوظيفة استدعاء واحدة تنفيذ مهمة بشكل مشروط استنادًا إلى ما فعلته وظيفة استدعاء أخرى في المكوّن الإضافي نفسه (على سبيل المثال، احتساب الفرق بين تشغيل requestWillFetch() وfetchDidSucceed() أو fetchDidFail()).

الإضافات التابعة لجهات خارجية

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

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

أخيرًا، إذا أنشأت مكوّنًا إضافيًا في Workbox تريد مشاركته، أضِف workbox-plugin الكلمة الرئيسية عند نشره. إذا كنت تستخدم هذه الميزة، يُرجى إعلامنا بذلك على Twitter ‎@WorkboxJS.