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

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

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

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

يوفّر Workbox المكوّنات الإضافية الرسمية التالية لاستخدامها في مشغّل الخدمات:

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

يتم استخدام مكوّنات Workspace الإضافية، سواء كانت أحد المكوّنات الإضافية المدرَجة أعلاه أو مكوّنات إضافية مخصّصة، مع استراتيجية Workspace من خلال إضافة مثيل من المكوّن الإضافي إلى 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 keyword عند نشره. إذا فعلت ذلك، يُرجى إعلامنا على Twitter @WorkboxJS.