הדרכה שכוללת מושגים בנושא Service Worker של תוספים
סקירה כללית
במדריך הזה ניתן מבוא ל-service workers של תוספי Chrome. במסגרת המדריך הזה, תיצרו תוסף שיאפשר למשתמשים לנווט במהירות לדפי הפניית ה-Chrome API באמצעות סרגל הכתובות. בשיעור הזה תלמדו איך:
- רושמים את קובץ השירות (service worker) ומייבאים מודולים.
- ניפוי באגים ב-service worker של התוסף.
- ניהול מצב וטיפול באירועים.
- הפעלת אירועים תקופתיים.
- תקשורת עם סקריפטים של תוכן.
לפני שמתחילים
במדריך הזה אנחנו יוצאים מנקודת הנחה שיש לכם ניסיון בסיסי בפיתוח אתרים. מומלץ לעיין במאמרים Extensions 101 ו-Hello World כדי לקבל מבוא לפיתוח תוספים.
יצירת התוסף
מתחילים ביצירת ספרייה חדשה בשם quick-api-reference כדי לאחסן את קובצי התוסף, או מורידים את קוד המקור ממאגר הדוגמאות ב-GitHub.
שלב 1: רישום של Service Worker
יוצרים את קובץ manifest בבסיס הפרויקט ומוסיפים את הקוד הבא:
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"
}
}
תוספים רושמים את ה-service worker שלהם במניפסט, שכולל רק קובץ JavaScript אחד.
אין צורך להתקשר אל navigator.serviceWorker.register(), כמו בדף אינטרנט.
יוצרים תיקייה בשם images ואז מורידים את הסמלים לתוכה.
במאמר השלבים הראשונים במדריך בנושא זמן קריאה אפשר לקרוא מידע נוסף על המטא-נתונים ועל הסמלים של התוסף במניפסט.
שלב 2: מייבאים כמה מודולים של Service Worker
ה-service worker שלנו מטמיע שתי תכונות. כדי לשפר את יכולת התחזוקה, נטמיע כל תכונה במודול נפרד. קודם צריך להצהיר על ה-service worker כמודול ES במניפסט, כדי שנוכל לייבא מודולים ל-service worker:
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");
במאמר ייבוא סקריפטים מוסבר על דרכים נוספות לייבוא של כמה קבצים ב-Service Worker.
אופציונלי: ניפוי באגים ב-Service Worker
אני אסביר איך למצוא את היומנים של Service Worker ואיך לדעת מתי הוא הסתיים. קודם כול, פועלים לפי ההוראות לטעינת תוסף לא ארוז.
אחרי 30 שניות תופיע ההודעה 'service worker (inactive)', כלומר, ה-service worker הסתיים. כדי לבדוק את ה-service worker, לוחצים על הקישור service worker (inactive) (סרוויס וורקר (לא פעיל)). אפשר לראות את זה באנימציה הבאה.
שמת לב שהבדיקה של קובץ השירות (service worker) הפעילה אותו? פתיחת ה-service worker בכלי הפיתוח תשמור אותו פעיל. כדי לוודא שהתוסף פועל בצורה תקינה כשמפסיקים את פעולת ה-service worker, חשוב לזכור לסגור את כלי הפיתוח.
עכשיו נשבור את התוסף כדי ללמוד איפה נמצאות השגיאות. אחת הדרכים לעשות זאת היא למחוק את התוסף .js מהשורה './sw-omnibox.js' import בקובץ service-worker.js. ל-Chrome לא תהיה אפשרות לרשום את קובץ השירות (service worker).
חוזרים אל chrome://extensions ומרעננים את התוסף. יוצגו שתי שגיאות:
Service worker registration failed. Status code: 3.
An unknown error occurred when fetching the script.
במאמר ניפוי באגים בתוספים מוסברות דרכים נוספות לניפוי באגים ב-Service Worker של התוסף.
שלב 4: הפעלת מצב התחלה
דפדפן Chrome ישבית את העובדים של שירותים אם אין בהם צורך. אנחנו משתמשים ב-API chrome.storage כדי לשמור את המצב בין סשנים של Service Worker. כדי לקבל גישה לאחסון, צריך לבקש הרשאה במניפסט:
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']
});
}
});
ל-Service workers אין גישה ישירה לאובייקט החלון, ולכן הם לא יכולים להשתמש ב-window.localStorage כדי לאחסן ערכים. בנוסף, service workers הם סביבות הרצה לטווח קצר. הם מסיימים את הפעולה שלהם שוב ושוב במהלך סשן הדפדפן של המשתמש, ולכן הם לא תואמים למשתנים גלובליים. במקום זאת, צריך להשתמש ב-chrome.storage.local ששומר נתונים במחשב המקומי.
מידע נוסף על אפשרויות אחסון אחרות ל-service workers של תוספים זמין במאמר שמירת נתונים במקום שימוש במשתנים גלובליים.
שלב 5: רושמים את האירועים
צריך לרשום את כל מאזיני האירועים באופן סטטי בהיקף הגלובלי של ה-service worker. במילים אחרות, אסור להטמיע מאזינים לאירועים בפונקציות אסינכרוניות. כך Chrome יכול לוודא שכל המטפלים באירועים ישוחזרו במקרה של הפעלה מחדש של Service Worker.
בדוגמה הזו נשתמש ב-API chrome.omnibox, אבל קודם צריך להצהיר על מילת המפתח להפעלת סרגל הכתובות במניפסט:
manifest.json:
{
...
"minimum_chrome_version": "102",
"omnibox": {
"keyword": "api"
},
}
עכשיו, רושמים את פונקציות ה-event listener של סרגל הכתובות ברמה העליונה של הסקריפט. כשהמשתמש מזין את מילת המפתח של סרגל הכתובות (api) בסרגל הכתובות ואחריה מקש Tab או רווח, 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() יפתח את דף הפניית ה-API המתאים ב-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() כדי לבצע משימות מושהות או תקופתיות. עם זאת, יכול להיות שה-API האלה ייכשלו כי המתזמן יבטל את הטיימרים כשה-service worker יופסק. במקום זאת, תוספים יכולים להשתמש ב-API 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: תקשורת עם הקשרים האחרים
תוספים משתמשים בסקריפטים של תוכן כדי לקרוא ולשנות את התוכן של הדף. כשמשתמש נכנס לדף הפניית API של Chrome, סקריפט התוכן של התוסף מעדכן את הדף עם טיפ היום. הוא שולח הודעה כדי לבקש את הטיפ היומי מ-Service Worker.
מתחילים בהצהרה על סקריפט התוכן במניפסט ומוסיפים את תבנית ההתאמה שמתאימה למסמכי העזרה של Chrome API.
manifest.json:
{
...
"content_scripts": [
{
"matches": ["https://developer.chrome.com/docs/extensions/reference/*"],
"js": ["content.js"]
}
]
}
יוצרים קובץ תוכן חדש. הקוד הבא שולח הודעה אל Service Worker ומבקש את הטיפ. אחר כך מוסיף כפתור שבלחיצה עליו ייפתח חלון קופץ עם הטיפ לגבי התוסף. הקוד הזה משתמש ב-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;
}
השלב האחרון הוא להוסיף ל-service worker שלנו פונקציית טיפול בהודעות, שתשלח תשובה לסקריפט התוכן עם הטיפ היומי.
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;
}
});
בודקים שהכול עובד
מוודאים שמבנה הקבצים של הפרויקט נראה כך:

טעינת התוסף באופן מקומי
כדי לטעון תוסף מסוג unpacked במצב פיתוח, פועלים לפי השלבים במאמר Hello world.
פתיחת דף עזר
- מזינים את מילת המפתח api בסרגל הכתובות של הדפדפן.
- מקישים על Tab או על מקש הרווח.
- מזינים את השם המלא של ה-API.
- או בוחרים מתוך רשימה של חיפושים קודמים
- ייפתח דף חדש עם הפניה ל-Chrome API.
הוא אמור להיראות כך:
פתיחת העצה היומית
לוחצים על לחצן הטיפ בסרגל הניווט כדי לפתוח את הטיפ של התוסף.
🎯 שיפורים אפשריים
בהתבסס על מה שלמדת היום, נסה לבצע אחת מהמשימות הבאות:
- אפשר לנסות דרך אחרת להטמיע את ההצעות בסרגל הכתובות.
- ליצור חלון קופץ מותאם אישית משלכם להצגת הטיפ לגבי התוסף.
- פותחים דף נוסף בדפי העזר של Web Extensions API ב-MDN.
ממשיכים לבנות!
כל הכבוד, סיימת את המדריך הזה 🎉. כדי להמשיך לשפר את הכישורים שלך, כדאי לעבור על מדריכים נוספים למתחילים:
| Extension | מה תלמדו |
|---|---|
| זמן קריאה | כדי להוסיף רכיב לקבוצה מסוימת של דפים באופן אוטומטי. |
| Tabs Manager | כדי ליצור חלון קופץ שמנהל כרטיסיות בדפדפן. |
| מצב פוקוס | כדי להריץ קוד בדף הנוכחי אחרי שלוחצים על פעולת התוסף. |
עוד מידע
כדי להמשיך את תוכנית הלימודים בנושא Service Worker של תוספים, מומלץ לעיין במאמרים הבאים: