التعامل مع الفعاليات مع موظفي الخدمات

دليل توجيهي يتناول مفاهيم مشغّلي الخدمات الإضافية

نظرة عامة

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

  • سجِّل مشغّل الخدمات وأدخِل الوحدات.
  • تصحيح أخطاء عامل خدمة الإضافة
  • إدارة الحالة والتعامل مع الأحداث
  • بدء أحداث دورية
  • التواصل مع النصوص البرمجية للمحتوى

قبل البدء

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

إنشاء الإضافة

ابدأ بإنشاء دليل جديد باسم quick-api-reference للاحتفاظ بملفات الإضافة، أو نزِّل رمز المصدر من مستودع نماذج GitHub.

الخطوة 1: تسجيل مشغّل الخدمات

أنشئ ملف البيان في جذر المشروع وأضِف الرمز التالي:

manifest.json:

{
  "manifest_version": 3,
  "name": "Open extension API reference",
  "version": "1.0.0",
  "icons": {
    "16": "images/icon-16.png",
    "128": "images/icon-128.png"
  },
  "background": {
    "service_worker": "service-worker.js"
  }
}

تسجِّل الإضافات مشغِّل الخدمات الخاص بها في البيان، الذي يأخذ ملف JavaScript واحدًا فقط. ليس هناك حاجة للاتصال بـ navigator.serviceWorker.register()، كما هو الحال في صفحة ويب.

أنشئ مجلدًا باسم images ثم نزِّل الرموز إليه.

يمكنك الاطّلاع على الخطوات الأولى في الدليل التعليمي الخاص بميزة "وقت القراءة" لمزيد من المعلومات حول البيانات الوصفية ورموز الإضافة في البيان.

الخطوة 2: استيراد وحدات مهام الخدمة المتعدّدة

عامل الخدمة ينفّذ ميزتين: لتحسين قابلية الصيانة، سننفّذ كل ميزة في وحدة منفصلة. أولاً، علينا تحديد الخدمة العاملة على أنّها وحدة ES في البيان، ما يسمح لنا باستيراد الوحدات في الخدمة العاملة:

manifest.json:

{
 "background": {
    "service_worker": "service-worker.js",
    "type": "module"
  },
}

أنشئ ملف service-worker.js واستورِد وحدتَين:

import './sw-omnibox.js';
import './sw-tips.js';

أنشئ هذه الملفات وأضف سجل وحدة تحكم إلى كل ملف.

sw-omnibox.js:

console.log("sw-omnibox.js");

sw-tips.js:

console.log("sw-tips.js");

اطّلِع على استيراد النصوص البرمجية للتعرّف على طرق أخرى لاستيراد ملفات متعددة في عامل خدمة.

اختياري: تصحيح أخطاء مشغِّل الخدمة

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

بعد 30 ثانية، ستظهر لك عبارة "عامل الخدمة (غير نشط)". ما يعني إنهاء مشغّل الخدمة. انقر على الرابط "عامل الخدمة (غير نشط)" لفحصه. توضِّح الصورة المتحركة التالية ذلك.

هل لاحظت أنّ فحص عامل الخدمة أدى إلى تنشيطه؟ سيؤدي فتح الخدمة العاملة في أدوات المطوّر إلى إبقائها نشطة. للتأكّد من أنّ الإضافة تعمل بشكل صحيح عند إنهاء مشغّل الخدمات، لا تنسَ إغلاق "أدوات مطوري البرامج".

الآن، يمكنك تقسيم الإضافة لمعرفة مكان تحديد الأخطاء. ويمكنك إجراء ذلك من خلال حذف " .js". من عملية استيراد './sw-omnibox.js' في ملف service-worker.js. لن يتمكن Chrome من تسجيل مشغّل الخدمات.

ارجع إلى chrome://extensions وأعِد تحميل الإضافة. ستظهر لك خطآن:

Service worker registration failed. Status code: 3.

An unknown error occurred when fetching the script.

اطّلِع على تصحيح أخطاء الإضافات للتعرّف على المزيد من الطرق لتصحيح أخطاء عامل الخدمة في الإضافة.

الخطوة 4: بدء الحالة

سيوقف Chrome خدمات "العامل" إذا لم تكن مطلوبة. نستخدم واجهة برمجة التطبيقات chrome.storage للحفاظ على الحالة في جميع جلسات الخدمة العاملة. للوصول إلى مساحة التخزين، علينا طلب إذن في ملف البيان:

manifest.json:

{
  ...
  "permissions": ["storage"],
}

أولاً، عليك حفظ الاقتراحات التلقائية في مساحة التخزين. يمكننا بدء الحالة عند تثبيت الإضافة لأول مرة من خلال الاستماع إلى حدث runtime.onInstalled():

sw-omnibox.js:

...
// Save default API suggestions
chrome.runtime.onInstalled.addListener(({ reason }) => {
  if (reason === 'install') {
    chrome.storage.local.set({
      apiSuggestions: ['tabs', 'storage', 'scripting']
    });
  }
});

لا يمكن لعمال الخدمة الوصول مباشرةً إلى عنصر النافذة، وبالتالي لا يمكنهم استخدام window.localStorage لتخزين القيم. كما أن عاملي الخدمات عبارة عن بيئات تنفيذ قصيرة الأجل؛ يتم إنهاؤها بشكل متكرر طوال جلسة متصفح المستخدم، مما يجعلها غير متوافقة مع والمتغيرات العمومية. بدلاً من ذلك، يمكنك استخدام أداة chrome.storage.local التي تخزِّن البيانات على الجهاز المحلي.

اطّلِع على تخزين البيانات بدلاً من استخدام المتغيّرات الشاملة للتعرّف على خيارات التخزين الأخرى لعمال خدمات الإضافات.

الخطوة 5: تسجيل الأحداث

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

في هذا المثال، سنستخدم واجهة برمجة التطبيقات chrome.omnibox، ولكن يجب أولاً الإعلان عن مشغِّل الكلمة الرئيسية للمربّع المتعدد الاستخدامات في البيان:

manifest.json:

{
  ...
  "minimum_chrome_version": "102",
  "omnibox": {
    "keyword": "api"
  },
}

الآن، سجِّل أدوات معالجة أحداث مربّع البحث الشامل في أعلى مستوى من النص البرمجي. عندما يُدخِل المستخدم الكلمة الرئيسية للمربّع المتعدّد الاستخدامات (api) في شريط العناوين متبوعة بعلامة تبويب أو مسافة، سيعرض Chrome قائمة بالاقتراحات استنادًا إلى الكلمات الرئيسية في مساحة التخزين. إنّ الحدث onInputChanged() الذي يأخذ إدخال المستخدم الحالي وعنصر suggestResult هو المسؤول عن تعبئة هذه الاقتراحات.

sw-omnibox.js:

...
const URL_CHROME_EXTENSIONS_DOC =
  'https://developer.chrome.com/docs/extensions/reference/';
const NUMBER_OF_PREVIOUS_SEARCHES = 4;

// Display the suggestions after user starts typing
chrome.omnibox.onInputChanged.addListener(async (input, suggest) => {
  await chrome.omnibox.setDefaultSuggestion({
    description: 'Enter a Chrome API or choose from past searches'
  });
  const { apiSuggestions } = await chrome.storage.local.get('apiSuggestions');
  const suggestions = apiSuggestions.map((api) => {
    return { content: api, description: `Open chrome.${api} API` };
  });
  suggest(suggestions);
});

بعد أن يختار المستخدم اقتراحًا، سيفتح onInputEntered() الصفحة المرجعية المقابلة لواجهة Chrome API.

sw-omnibox.js:

...
// Open the reference page of the chosen API
chrome.omnibox.onInputEntered.addListener((input) => {
  chrome.tabs.create({ url: URL_CHROME_EXTENSIONS_DOC + input });
  // Save the latest keyword
  updateHistory(input);
});

تستخدم الدالة updateHistory() إدخال المربّع المتعدد الاستخدامات وتحفظه في storage.local. بهذه الطريقة، يمكن استخدام أحدث عبارة بحث لاحقًا كاقتراح في المربّع المتعدد الاستخدامات.

sw-omnibox.js:

...
async function updateHistory(input) {
  const { apiSuggestions } = await chrome.storage.local.get('apiSuggestions');
  apiSuggestions.unshift(input);
  apiSuggestions.splice(NUMBER_OF_PREVIOUS_SEARCHES);
  return chrome.storage.local.set({ apiSuggestions });
}

الخطوة 6: إعداد حدث متكرّر

يتم عادةً استخدام الطريقة setTimeout() أو setInterval() لتنفيذ الإجراءات المتأخرة أو الدورية. المهام. ومع ذلك، يمكن أن تتعذّر هذه واجهات برمجة التطبيقات لأنّ المخطِّط سيلغي الموقّتات عند إنهاء الخدمة العملية. بدلاً من ذلك، يمكن للإضافات استخدام واجهة برمجة تطبيقات chrome.alarms.

يمكنك البدء بطلب إذن ""alarms"" في ملف البيان. بالإضافة إلى ذلك، لجلب نصائح الإضافة من موقع مستضاف بعيد، عليك طلب إذن المضيف:

manifest.json:

{
  ...
  "permissions": ["storage"],
  "permissions": ["storage", "alarms"],
  "host_permissions": ["https://extension-tips.glitch.me/*"],
}

ستجلب الإضافة جميع النصائح، واختَر إحداها عشوائيًا واحفظها في مساحة التخزين. وسنُنشئ تنبيهًا لتشغيله مرة واحدة في اليوم لتعديل النصيحة. لا يتم حفظ التنبيهات عند إغلاق Chrome. لذلك نحن بحاجة إلى التحقق من وجود المنبه وإنشائه إن لم يكن كذلك.

sw-tips.js:

// Fetch tip & save in storage
const updateTip = async () => {
  const response = await fetch('https://extension-tips.glitch.me/tips.json');
  const tips = await response.json();
  const randomIndex = Math.floor(Math.random() * tips.length);
  return chrome.storage.local.set({ tip: tips[randomIndex] });
};

const ALARM_NAME = 'tip';

// Check if alarm exists to avoid resetting the timer.
// The alarm might be removed when the browser session restarts.
async function createAlarm() {
  const alarm = await chrome.alarms.get(ALARM_NAME);
  if (typeof alarm === 'undefined') {
    chrome.alarms.create(ALARM_NAME, {
      delayInMinutes: 1,
      periodInMinutes: 1440
    });
    updateTip();
  }
}

createAlarm();

// Update tip once a day
chrome.alarms.onAlarm.addListener(updateTip);

الخطوة 7: التواصل مع السياقات الأخرى

تستخدِم الإضافات نصوص برمجية للمحتوى لقراءة محتوى الصفحة وتعديله. عندما يزور أحد المستخدمين صفحة مرجعية لواجهة برمجة تطبيقات Chrome، سيعمل النص البرمجي لمحتوى الإضافة على تحديث الصفحة بنصيحة اليوم. يرسل رسالة لطلب نصيحة اليوم من عامل الخدمة.

ابدأ بتعريف النص البرمجي للمحتوى في البيان وإضافة نمط المطابقة المقابل للمستندات المرجعية لواجهة Chrome API.

manifest.json:

{
  ...
  "content_scripts": [
    {
      "matches": ["https://developer.chrome.com/docs/extensions/reference/*"],
      "js": ["content.js"]
    }
  ]
}

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

content.js:

(async () => {
  // Sends a message to the service worker and receives a tip in response
  const { tip } = await chrome.runtime.sendMessage({ greeting: 'tip' });

  const nav = document.querySelector('.upper-tabs > nav');
  
  const tipWidget = createDomElement(`
    <button type="button" popovertarget="tip-popover" popovertargetaction="show" style="padding: 0 12px; height: 36px;">
      <span style="display: block; font: var(--devsite-link-font,500 14px/20px var(--devsite-primary-font-family));">Tip</span>
    </button>
  `);

  const popover = createDomElement(
    `<div id='tip-popover' popover style="margin: auto;">${tip}</div>`
  );

  document.body.append(popover);
  nav.append(tipWidget);
})();

function createDomElement(html) {
  const dom = new DOMParser().parseFromString(html, 'text/html');
  return dom.body.firstElementChild;
}

الخطوة الأخيرة هي إضافة معالج رسائل إلى مشغّل الخدمات الذي يرسل ردًا على النص البرمجي للمحتوى مع النصيحة اليومية.

sw-tips.js:

...
// Send tip to content script via messaging
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
  if (message.greeting === 'tip') {
    chrome.storage.local.get('tip').then(sendResponse);
    return true;
  }
});

اختبار صلاحية الإعدادات

تأكَّد من أنّ بنية ملف مشروعك تظهر على النحو التالي:

تتضمن محتويات مجلد الإضافة: ملف الصور، وملف البيان.json، والخدمة-worker.js، وsw-omnibox.js، وsw-tips.js،
وcontent.js

تحميل الإضافة محليًا

لتحميل إضافة غير مضغوطة في وضع المطوّر، اتّبِع الخطوات الواردة في مرحبًا بك.

فتح صفحة مرجعية

  1. أدخِل الكلمة الرئيسية "api" في شريط عناوين المتصفّح.
  2. اضغط على مفتاح التبويب (Tab) أو مفتاح المسافة (Space).
  3. أدخِل الاسم الكامل لواجهة برمجة التطبيقات.
    • أو اختر من قائمة عمليات البحث السابقة
  4. ستفتح صفحة جديدة تنقل إلى صفحة مرجع Chrome API.

من المفترض أن يظهر الرمز على النحو التالي:

مرجع سريع لواجهة برمجة التطبيقات يفتح مرجع واجهة برمجة التطبيقات لوقت التشغيل
إضافة Quick API التي تفتح واجهة Runtime API

فتح نصيحة اليوم

انقر على الزر "نصيحة" في شريط التنقل لفتح نصيحة الإضافة.

فتح النصيحة اليومية في
إضافة Quick API في نصيحة اليوم.

🎯 التحسينات المحتمَلة

بناءً على ما تعلمته اليوم، حاول تحقيق أي مما يلي:

  • تعرَّف على طريقة أخرى لتنفيذ اقتراحات مربّع البحث الشامل.
  • أنشئ نافذة منبثقة مخصّصة لعرض نصيحة الإضافة.
  • فتح صفحة إضافية تنقل إلى صفحات واجهة برمجة التطبيقات المرجعية لإضافات الويب في MDN

استمر في البناء!

تهانينا على إكمال هذا الدليل التعليمي 🎉. يمكنك مواصلة تحسين مهاراتك من خلال إكمال أنشطة دروس تعليمية للمبتدئين:

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

الاطّلاع على معلومات إضافية

لمواصلة المسار التعليمي لعاملي الخدمات الإضافية، ننصحك بالاطّلاع على المقالات التالية: