برنامج تعليمي يغطّي مفاهيم عاملي خدمة الإضافات
نظرة عامة
يقدّم هذا البرنامج التعليمي مقدمة عن عاملي الخدمة في إضافات 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 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;
}
});
اختبار ما إذا كان يعمل
تأكَّد من أنّ بنية ملف مشروعك تبدو على النحو التالي:
تحميل الإضافة على جهازك
لتحميل إضافة غير مضغوطة في وضع "مطوّر البرامج"، اتّبِع الخطوات الواردة في Hello world.
فتح صفحة مرجعية
- أدخِل الكلمة الرئيسية "api" في شريط عناوين المتصفّح.
- اضغط على مفتاح Tab أو مفتاح المسافة.
- أدخِل الاسم الكامل لواجهة برمجة التطبيقات.
- أو الاختيار من قائمة بعمليات البحث السابقة
- سيتم فتح صفحة جديدة تعرض صفحة مرجع Chrome API.
يجب أن يظهر على النحو التالي:

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

🎯 التحسينات المحتملة
استنادًا إلى ما تعلّمته اليوم، حاوِل إنجاز أيّ مما يلي:
- استكشاف طريقة أخرى لتنفيذ اقتراحات شريط العناوين الشامل
- أنشئ نافذة مشروطة مخصّصة لعرض تلميح الإضافة.
- فتح صفحة إضافية لصفحات واجهة برمجة التطبيقات المرجعية الخاصة بإضافات الويب على شبكة مطوّري Mozilla
ننصحك بمواصلة بناء المنتدى.
تهانينا على إكمال هذا الدليل التعليمي 🎉. يمكنك مواصلة تطوير مهاراتك من خلال إكمال أدلة تعليمية أخرى للمبتدئين:
الإضافة | ما ستتعلمه |
---|---|
وقت القراءة | لإدراج عنصر في مجموعة معيّنة من الصفحات تلقائيًا، اتّبِع الخطوات التالية: |
Tabs Manager | لإنشاء نافذة منبثقة تدير علامات تبويب المتصفّح، اتّبِع الخطوات التالية: |
وضع التركيز | لتنفيذ الرمز على الصفحة الحالية بعد النقر على إجراء الإضافة |
الاطّلاع على معلومات إضافية
لمواصلة مسار التعلّم الخاص بعامل خدمة الإضافة، ننصحك بالاطّلاع على المقالات التالية: