برنامج تعليمي يتناول مفاهيم مشغّل خدمات الإضافة
نظرة عامة
يقدّم هذا البرنامج التعليمي مقدمة عن مشغّلي خدمات إضافات Chrome. كجزء من هذا البرنامج التعليمي، ستنشئ إضافة تتيح للمستخدمين الانتقال بسرعة إلى صفحات مرجع واجهة برمجة تطبيقات Chrome باستخدام المربّع متعدد الاستخدامات. ستتعرّف على كيفية:
- تسجيل مشغّل الخدمات واستيراد الوحدات
- تصحيح أخطاء مشغّل خدمات الإضافة
- إدارة الحالة والتعامل مع الأحداث
- تفعيل الأحداث الدورية
- التواصل مع النصوص البرمجية للمحتوى
قبل البدء
يفترض هذا الدليل أنّ لديك خبرة أساسية في تطوير الويب. ننصحك بمراجعة الدليل الإرشادي للإضافات وHello World للحصول على مقدمة عن تطوير الإضافات.
إنشاء الإضافة
ابدأ بإنشاء دليل جديد باسم 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 المقابلة.
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"],
}
ستجلب الإضافة جميع النصائح وتختار واحدة عشوائيًا وتحفظها في مساحة التخزين. سننشئ منبّهًا سيتم تفعيله مرة واحدة في اليوم لتعديل النصيحة. لا يتم حفظ المنبّهات عند إغلاق Chrome. لذا، علينا التحقّق مما إذا كان المنبّه موجودًا وإنشاؤه إذا لم يكن كذلك.
sw-tips.js:
// Fetch tip & save in storage
const updateTip = async () => {
const response = await fetch('https://chrome.dev/f/extension_tips/');
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.
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;
}
});
اختبار ما إذا كانت الإضافة تعمل
تأكَّد من أنّ بنية ملفات مشروعك تبدو على النحو التالي:

تحميل الإضافة محليًا
لتحميل إضافة متاحة في وضع مطوّر البرامج، اتّبِع الخطوات الواردة في مقالة Hello world.
فتح صفحة مرجع
- أدخِل الكلمة الرئيسية "api" في شريط عناوين المتصفّح.
- اضغط على "علامة التبويب" أو "المسافة".
- أدخِل الاسم الكامل لواجهة برمجة التطبيقات.
- أو اختَر من قائمة عمليات البحث السابقة.
- سيتم فتح صفحة جديدة لصفحة مرجع واجهة برمجة تطبيقات Chrome.
يجب أن تبدو على النحو التالي:
فتح نصيحة اليوم
انقر على الزر "نصيحة" في شريط التنقّل لفتح نصيحة الإضافة.
🎯 التحسينات المحتملة
استنادًا إلى ما تعلّمته اليوم، حاوِل تنفيذ أي مما يلي:
- استكشاف طريقة أخرى لتنفيذ اقتراحات المربّع متعدد الاستخدامات
- إنشاء نموذج مخصّص لعرض نصيحة الإضافة
- فتح صفحة إضافية لصفحات مرجع واجهة برمجة تطبيقات Web Extensions في MDN
لنواصل البناء!
تهانينا على إكمال هذا البرنامج التعليمي 🎉. واصِل تحسين مهاراتك من خلال إكمال البرامج التعليمية الأخرى للمبتدئين:
| الإضافة | ما ستتعلمه |
|---|---|
| وقت القراءة | إدراج عنصر تلقائيًا في مجموعة معيّنة من الصفحات |
| مدير علامات التبويب | إنشاء نافذة منبثقة تدير علامات تبويب المتصفّح |
| وضع التركيز | تشغيل الرمز على الصفحة الحالية بعد النقر على إجراء الإضافة |
مزيد من المعلومات
لمواصلة مسار تعلّم مشغّل خدمات الإضافة، ننصحك باستكشاف المقالات التالية: