บทแนะนำที่ครอบคลุมแนวคิดเกี่ยวกับ Service Worker ของส่วนขยาย
ภาพรวม
บทแนะนำนี้จะแนะนำ Service Worker ของส่วนขยาย Chrome ในส่วนหนึ่งของบทแนะนำนี้ คุณจะได้สร้างส่วนขยายที่ช่วยให้ผู้ใช้ไปยังหน้าอ้างอิง Chrome API ได้อย่างรวดเร็วโดยใช้ช่องอเนกประสงค์ คุณจะได้เรียนรู้วิธีต่อไปนี้
- ลงทะเบียน Service Worker และนำเข้าโมดูล
- แก้ไขข้อบกพร่องของ Service Worker ของส่วนขยาย
- จัดการสถานะและจัดการเหตุการณ์
- ทริกเกอร์เหตุการณ์เป็นระยะ
- สื่อสารด้วยสคริปต์เนื้อหา
ก่อนจะเริ่มต้น
คู่มือนี้จะถือว่าคุณมีประสบการณ์ด้านการพัฒนาเว็บขั้นพื้นฐาน เราขอแนะนำให้คุณอ่านส่วนขยายเบื้องต้นและ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 ในไฟล์ Manifest ซึ่งใช้ไฟล์ JavaScript เพียงไฟล์เดียว
คุณไม่จำเป็นต้องเรียกใช้ navigator.serviceWorker.register() เหมือนในหน้าเว็บ
สร้างโฟลเดอร์ images จากนั้นดาวน์โหลดไอคอนลงในโฟลเดอร์
ดูขั้นตอนแรกของบทแนะนำเวลาในการอ่านเพื่อดูข้อมูลเพิ่มเติมเกี่ยวกับข้อมูลเมตาและไอคอนของส่วนขยายในไฟล์ Manifest
ขั้นตอนที่ 2: นำเข้าโมดูล Service Worker หลายโมดูล
Service Worker ของเราจะใช้ฟีเจอร์ 2 อย่าง เราจะติดตั้งใช้งานฟีเจอร์แต่ละอย่างในโมดูลแยกต่างหากเพื่อให้ดูแลรักษาได้ดียิ่งขึ้น ก่อนอื่น เราต้องประกาศ Service Worker เป็น ES Module ในไฟล์ Manifest ซึ่งจะช่วยให้เรานำเข้าโมดูลใน Service Worker ได้
manifest.json:
{
"background": {
"service_worker": "service-worker.js",
"type": "module"
},
}
สร้างไฟล์ service-worker.js แล้วนำเข้า 2 โมดูล
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 และวิธีทราบว่า Service Worker สิ้นสุดการทำงานแล้วเมื่อใด ก่อนอื่น ให้ทำตามวิธีการเพื่อโหลดส่วนขยายที่ไม่ได้แพ็ก
หลังจากผ่านไป 30 วินาที คุณจะเห็นข้อความ "Service Worker (ไม่ได้ใช้งาน)" ซึ่งหมายความว่า Service Worker สิ้นสุดการทำงานแล้ว คลิกลิงก์ "Service Worker (ไม่ได้ใช้งาน)" เพื่อตรวจสอบ ภาพเคลื่อนไหวต่อไปนี้แสดงให้เห็นถึงการทำงานนี้
คุณสังเกตไหมว่าการตรวจสอบ Service Worker ทำให้ Service Worker ทำงาน การเปิด Service Worker ใน DevTools จะทำให้ Service Worker ทำงานอยู่ อย่าลืมปิด DevTools เพื่อให้มั่นใจว่าส่วนขยายจะทำงานได้อย่างถูกต้องเมื่อ Service Worker สิ้นสุดการทำงาน
ตอนนี้ให้แยกส่วนขยายเพื่อดูว่าข้อผิดพลาดอยู่ที่ใด วิธีหนึ่งในการทำเช่นนี้คือการลบ ".js" ออกจากคำสั่ง './sw-omnibox.js' import ในไฟล์ service-worker.js Chrome จะลงทะเบียน Service Worker ไม่ได้
กลับไปที่ chrome://extensions แล้วรีเฟรชส่วนขยาย คุณจะเห็นข้อผิดพลาด 2 รายการดังนี้
Service worker registration failed. Status code: 3.
An unknown error occurred when fetching the script.
ดูวิธีอื่นๆ ในการแก้ไขข้อบกพร่องของ Service Worker ของส่วนขยายได้ที่การแก้ไขข้อบกพร่องของส่วนขยาย
ขั้นตอนที่ 4: เริ่มต้นสถานะ
Chrome จะปิด Service Worker หากไม่จำเป็น เราใช้ API ของ browser.storage เพื่อคงสถานะไว้ในเซสชันของ Service Worker สำหรับการเข้าถึงพื้นที่เก็บข้อมูล เราต้องขอสิทธิ์ในไฟล์ Manifest ดังนี้
manifest.json:
{
...
"permissions": ["storage"],
}
ก่อนอื่น ให้บันทึกคำแนะนำเริ่มต้นลงในที่เก็บข้อมูล เราสามารถเริ่มต้นสถานะเมื่อติดตั้งส่วนขยายเป็นครั้งแรกได้โดยการฟังเหตุการณ์ runtime.onInstalled() ดังนี้
sw-omnibox.js:
...
// Save default API suggestions
browser.runtime.onInstalled.addListener(({ reason }) => {
if (reason === 'install') {
browser.storage.local.set({
apiSuggestions: ['tabs', 'storage', 'scripting']
});
}
});
Service Worker ไม่มีสิทธิ์เข้าถึงออบเจ็กต์หน้าต่างโดยตรง จึงใช้
window.localStorage เพื่อจัดเก็บค่าไม่ได้ นอกจากนี้ Service Worker ยังเป็นสภาพแวดล้อมการดำเนินการที่มีอายุสั้น
โดยจะสิ้นสุดซ้ำๆ ตลอดเซสชันเบราว์เซอร์ของผู้ใช้ ซึ่งทำให้ไม่สามารถใช้กับ
ตัวแปรส่วนกลางได้ แต่ให้ใช้ browser.storage.local แทน ซึ่งจะจัดเก็บข้อมูลไว้ในเครื่อง
ดูข้อมูลเกี่ยวกับตัวเลือกพื้นที่เก็บข้อมูลอื่นๆ สำหรับ Service Worker ของส่วนขยายได้ที่เก็บข้อมูลไว้แทนการใช้ตัวแปรส่วนกลาง
ขั้นตอนที่ 5: ลงทะเบียนกิจกรรม
ต้องลงทะเบียนเครื่องมือฟังเหตุการณ์ทั้งหมดแบบคงที่ในขอบเขตส่วนกลางของ Service Worker กล่าวคือ ไม่ควรซ้อน Listener ของเหตุการณ์ในฟังก์ชันแบบไม่พร้อมกัน วิธีนี้จะช่วยให้ Chrome มั่นใจได้ว่าระบบจะกู้คืนตัวแฮนเดิลเหตุการณ์ทั้งหมดในกรณีที่ Service Worker รีบูต
ในตัวอย่างนี้ เราจะใช้ API ของ browser.omnibox แต่ก่อนอื่นเราต้องประกาศทริกเกอร์คีย์เวิร์ดของ Omnibox ในไฟล์ Manifest ดังนี้
manifest.json:
{
...
"minimum_chrome_version": "102",
"omnibox": {
"keyword": "api"
},
}
ตอนนี้ ให้ลงทะเบียน Listener เหตุการณ์ของช่องออมนิบ็อกซ์ที่ระดับบนสุดของสคริปต์ เมื่อผู้ใช้ป้อนคีย์เวิร์ดของแถบอเนกประสงค์ (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
browser.omnibox.onInputChanged.addListener(async (input, suggest) => {
await browser.omnibox.setDefaultSuggestion({
description: 'Enter a Chrome API or choose from past searches'
});
const { apiSuggestions } = await browser.storage.local.get('apiSuggestions');
const suggestions = apiSuggestions.map((api) => {
return { content: api, description: `Open browser.${api} API` };
});
suggest(suggestions);
});
หลังจากผู้ใช้เลือกคำแนะนำแล้ว onInputEntered() จะเปิดหน้าเอกสารอ้างอิง API ของ Chrome ที่เกี่ยวข้อง
sw-omnibox.js:
...
// Open the reference page of the chosen API
browser.omnibox.onInputEntered.addListener((input) => {
browser.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 browser.storage.local.get('apiSuggestions');
apiSuggestions.unshift(input);
apiSuggestions.splice(NUMBER_OF_PREVIOUS_SEARCHES);
return browser.storage.local.set({ apiSuggestions });
}
ขั้นตอนที่ 6: ตั้งค่ากิจกรรมที่เกิดซ้ำ
โดยทั่วไปจะใช้วิธี setTimeout() หรือ setInterval() เพื่อดำเนินการที่ล่าช้าหรือเป็นระยะ
อย่างไรก็ตาม API เหล่านี้อาจทำงานไม่สำเร็จเนื่องจากตัวกำหนดเวลาจะยกเลิกตัวจับเวลาเมื่อ Service Worker สิ้นสุดการทำงาน แต่ส่วนขยายสามารถใช้ browser.alarms API แทนได้
เริ่มต้นด้วยการขอสิทธิ์ "alarms" ในไฟล์ Manifest ดังนี้
manifest.json:
{
...
"permissions": ["storage"],
"permissions": ["storage", "alarms"],
}
ส่วนขยายจะดึงเคล็ดลับทั้งหมด เลือกมา 1 รายการแบบสุ่ม แล้วบันทึกลงในพื้นที่เก็บข้อมูล เราจะสร้างการปลุกที่จะทำงานวันละครั้งเพื่ออัปเดตเคล็ดลับ ระบบจะไม่บันทึกการปลุกเมื่อคุณปิด 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 browser.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 browser.alarms.get(ALARM_NAME);
if (typeof alarm === 'undefined') {
browser.alarms.create(ALARM_NAME, {
delayInMinutes: 1,
periodInMinutes: 1440
});
updateTip();
}
}
createAlarm();
// Update tip once a day
browser.alarms.onAlarm.addListener(updateTip);
ขั้นตอนที่ 7: สื่อสารกับบริบทอื่นๆ
ส่วนขยายใช้สคริปต์เนื้อหาเพื่ออ่านและแก้ไขเนื้อหาของหน้าเว็บ เมื่อผู้ใช้เข้าชมหน้าอ้างอิง Chrome API สคริปต์เนื้อหาของส่วนขยายจะอัปเดตหน้าเว็บด้วยเคล็ดลับประจำวัน โดยจะส่งข้อความเพื่อขอเคล็ดลับประจำวันจาก Service Worker
เริ่มต้นด้วยการประกาศ Content Script ในไฟล์ Manifest และเพิ่มรูปแบบการจับคู่ที่สอดคล้องกับเอกสารอ้างอิง 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 browser.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 ที่ส่งการตอบกลับไปยัง Content Script พร้อมเคล็ดลับประจำวัน
sw-tips.js:
...
// Send tip to content script via messaging
browser.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.greeting === 'tip') {
browser.storage.local.get('tip').then(sendResponse);
return true;
}
});
ทดสอบว่าใช้งานได้
ตรวจสอบว่าโครงสร้างไฟล์ของโปรเจ็กต์มีลักษณะดังนี้

โหลดส่วนขยายในเครื่อง
หากต้องการโหลดส่วนขยายที่คลายการแพคในโหมดนักพัฒนาซอฟต์แวร์ ให้ทำตามขั้นตอนในHello world
เปิดหน้าอ้างอิง
- ป้อนคีย์เวิร์ด "api" ในแถบที่อยู่ของเบราว์เซอร์
- กด "Tab" หรือ "Space"
- ป้อนชื่อ API แบบเต็ม
- หรือเลือกจากรายการการค้นหาที่ผ่านมา
- ระบบจะเปิดหน้าใหม่ไปยังหน้าอ้างอิง Chrome API
ซึ่งควรมีลักษณะดังนี้
เปิดเคล็ดลับประจำวัน
คลิกปุ่มเคล็ดลับที่อยู่ในแถบนำทางเพื่อเปิดเคล็ดลับของส่วนขยาย
🎯 การปรับปรุงที่อาจเกิดขึ้น
จากสิ่งที่ได้เรียนรู้ในวันนี้ ให้ลองทำสิ่งต่อไปนี้
- ดูวิธีอื่นในการใช้คำแนะนำในแถบอเนกประสงค์
- สร้างโมดัลที่กำหนดเองเพื่อแสดงเคล็ดลับส่วนขยาย
- เปิดหน้าเพิ่มเติมไปยังหน้า API อ้างอิงส่วนขยายเว็บของ MDN
สร้างสรรค์ต่อไป
ขอแสดงความยินดีที่ดูบทแนะนำนี้จนจบ 🎉 โปรดพัฒนาทักษะต่อไปโดยดูบทแนะนำอื่นๆ สำหรับผู้เริ่มต้น ให้จบ
| ส่วนขยาย | สิ่งที่คุณจะได้เรียนรู้ |
|---|---|
| เวลาในการอ่าน | หากต้องการแทรกองค์ประกอบในชุดหน้าที่เฉพาะเจาะจงโดยอัตโนมัติ |
| Tabs Manager | สร้างป๊อปอัปที่จัดการแท็บเบราว์เซอร์ |
| โหมดโฟกัส | หากต้องการเรียกใช้โค้ดในหน้าปัจจุบันหลังจากคลิกการดำเนินการของส่วนขยาย |
สำรวจต่อ
หากต้องการศึกษาเส้นทางการเรียนรู้ Service Worker ของส่วนขยายต่อไป เราขอแนะนำให้อ่านบทความต่อไปนี้