Menangani peristiwa dengan pekerja layanan

Tutorial yang mencakup konsep pekerja layanan ekstensi

Ringkasan

Tutorial ini memberikan pengantar untuk pekerja layanan Ekstensi Chrome. Sebagai bagian dari tutorial ini, Anda akan membuat ekstensi yang memungkinkan pengguna membuka halaman referensi API Chrome dengan cepat menggunakan omnibox. Anda akan belajar cara:

  • Mendaftarkan pekerja layanan dan mengimpor modul.
  • Men-debug pekerja layanan ekstensi Anda.
  • Mengelola status dan menangani peristiwa.
  • Memicu peristiwa berkala.
  • Berkomunikasi dengan skrip konten.

Sebelum memulai

Panduan ini mengasumsikan bahwa Anda memiliki pengalaman pengembangan web dasar. Sebaiknya tinjau Ekstensi 101 dan Halo Dunia untuk pengantar pengembangan ekstensi.

Mem-build ekstensi

Mulai dengan membuat direktori baru bernama quick-api-reference untuk menyimpan file ekstensi, atau mendownload kode sumber dari repositori contoh GitHub kami.

Langkah 1: Mendaftarkan pekerja layanan

Buat file manifes di root project dan tambahkan kode berikut:

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",
  },
}

Ekstensi mendaftarkan pekerja layanannya dalam manifes, yang hanya mengambil satu file JavaScript. Tidak perlu memanggil navigator.serviceWorker.register(), seperti yang Anda lakukan di halaman web.

Buat folder images, lalu download ikon ke dalamnya.

Lihat langkah-langkah pertama tutorial Waktu membaca untuk mempelajari lebih lanjut metadata dan ikon ekstensi dalam manifes.

Langkah 2: Impor beberapa modul pekerja layanan

Pekerja layanan kami mengimplementasikan dua fitur. Untuk pemeliharaan yang lebih baik, kami akan mengimplementasikan setiap fitur dalam modul terpisah. Pertama, kita perlu mendeklarasikan pekerja layanan sebagai Modul ES dalam manifes, yang memungkinkan kita mengimpor modul dalam pekerja layanan:

manifest.json:

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

Buat file service-worker.js dan impor dua modul:

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

Buat file ini dan tambahkan log konsol ke setiap file.

sw-omnibox.js:

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

sw-tips.js:

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

Lihat Mengimpor skrip untuk mempelajari cara lain mengimpor beberapa file dalam pekerja layanan.

Opsional: Men-debug pekerja layanan

Saya akan menjelaskan cara menemukan log pekerja layanan dan mengetahui kapan layanan tersebut dihentikan. Pertama, ikuti petunjuk untuk Memuat ekstensi yang belum dibuka.

Setelah 30 detik Anda akan melihat "pekerja layanan (tidak aktif)" yang berarti pekerja layanan telah dihentikan. Klik link "pekerja layanan (tidak aktif)" untuk memeriksanya. Animasi berikut menunjukkan hal ini.

Apakah Anda memperhatikan bahwa memeriksa pekerja layanan akan membangunkannya? Membuka pekerja layanan di devtools akan membuatnya aktif. Untuk memastikan ekstensi berperilaku dengan benar saat pekerja layanan dihentikan, jangan lupa untuk menutup DevTools.

Sekarang, hentikan ekstensi untuk mempelajari tempat menemukan error. Salah satu cara untuk melakukannya adalah dengan menghapus ".js" dari impor './sw-omnibox.js' di file service-worker.js. Chrome tidak akan dapat mendaftarkan pekerja layanan.

Kembali ke chrome://extensions, lalu muat ulang ekstensi. Anda akan melihat dua error:

Service worker registration failed. Status code: 3.

An unknown error occurred when fetching the script.

Lihat Men-debug ekstensi untuk mengetahui cara lainnya dalam men-debug pekerja layanan ekstensi.

Langkah 4: Melakukan inisialisasi status

Chrome akan menonaktifkan pekerja layanan jika tidak diperlukan. Kita menggunakan chrome.storage API untuk mempertahankan status di seluruh sesi pekerja layanan. Untuk akses penyimpanan, kita perlu meminta izin dalam manifes:

manifest.json:

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

Pertama, simpan saran default ke penyimpanan. Kita dapat menginisialisasi status saat ekstensi pertama kali diinstal dengan memproses peristiwa 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']
    });
  }
});

Pekerja layanan tidak memiliki akses langsung ke objek jendela sehingga tidak dapat menggunakan window.localStorage untuk menyimpan nilai. Selain itu, pekerja layanan adalah lingkungan eksekusi yang berumur singkat; mereka dihentikan berulang kali selama sesi browser pengguna, yang membuatnya tidak kompatibel dengan variabel global. Sebagai gantinya, gunakan chrome.storage.local yang menyimpan data di komputer lokal.

Lihat Mempertahankan data, bukan menggunakan variabel global, guna mempelajari opsi penyimpanan lainnya untuk pekerja layanan ekstensi.

Langkah 5: Daftarkan peristiwa

Semua pemroses peristiwa harus terdaftar secara statis dalam cakupan global pekerja layanan. Dengan kata lain, pemroses peristiwa tidak boleh disarangkan dalam fungsi asinkron. Dengan cara ini, Chrome dapat memastikan bahwa semua pengendali peristiwa dipulihkan jika pekerja layanan dimulai ulang.

Dalam contoh ini, kita akan menggunakan chrome.omnibox API, tetapi pertama-tama kita harus mendeklarasikan pemicu kata kunci omnibox dalam manifes:

manifest.json:

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

Sekarang, daftarkan pemroses peristiwa omnibox di tingkat teratas skrip. Saat pengguna memasukkan kata kunci omnibox (api) di kolom URL, diikuti dengan tab atau spasi, Chrome akan menampilkan daftar saran berdasarkan kata kunci di penyimpanan. Peristiwa onInputChanged(), yang mengambil input pengguna saat ini dan objek suggestResult, bertanggung jawab untuk mengisi saran ini.

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);
});

Setelah pengguna memilih saran, onInputEntered() akan membuka halaman referensi Chrome API yang sesuai.

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);
});

Fungsi updateHistory() mengambil input omnibox dan menyimpannya ke storage.local. Dengan cara ini, istilah penelusuran terbaru dapat digunakan di lain waktu sebagai saran omnibox.

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 });
}

Langkah 6: Siapkan acara rutin

Metode setTimeout() atau setInterval() biasanya digunakan untuk melakukan tugas yang tertunda atau bertahap. Namun, API ini bisa gagal karena penjadwal akan membatalkan timer saat pekerja layanan dihentikan. Sebagai gantinya, ekstensi dapat menggunakan chrome.alarms API.

Mulailah dengan meminta izin "alarms" dalam manifes. Selain itu, untuk mengambil tips ekstensi dari lokasi yang dihosting jarak jauh, Anda harus meminta izin host:

manifest.json:

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

Ekstensi akan mengambil semua tips, memilih satu secara acak, dan menyimpannya ke penyimpanan. Kami akan membuat alarm yang akan dipicu sekali sehari untuk memperbarui tips. Alarm tidak disimpan saat Anda menutup Chrome. Jadi kita perlu memeriksa apakah alarm ada dan membuatnya jika tidak ada.

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);

Langkah 7: Berkomunikasi dengan konteks lain

Ekstensi menggunakan skrip konten untuk membaca dan mengubah konten halaman. Saat pengguna mengunjungi halaman referensi Chrome API, skrip konten ekstensi akan memperbarui halaman dengan akhir hari. Fungsi ini mengirim pesan untuk meminta tip hari dari pekerja layanan.

Mulailah dengan mendeklarasikan skrip konten dalam manifes dan menambahkan pola pencocokan yang sesuai dengan dokumentasi referensi Chrome API.

manifest.json:

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

Membuat file konten baru. Kode berikut mengirimkan pesan ke pekerja layanan yang meminta tip. Kemudian, tambahkan tombol yang akan membuka popover yang berisi tips ekstensi. Kode ini menggunakan platform web baru 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;
}

Langkah terakhir adalah menambahkan pengendali pesan ke pekerja layanan yang akan mengirimkan balasan ke skrip konten dengan tip harian.

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;
  }
});

Menguji performa

Pastikan struktur file project Anda terlihat seperti berikut:

Konten folder ekstensi: folder images, manifest.json, service-worker.js, sw-omnibox.js, sw-tips.js,
dan content.js

Memuat ekstensi secara lokal

Untuk memuat ekstensi yang belum dibuka dalam mode developer, ikuti langkah-langkah dalam artikel Halo Dunia.

Membuka halaman referensi

  1. Masukkan kata kunci "api" di kolom URL browser.
  2. Tekan "tab" atau "spasi".
  3. Masukkan nama lengkap API.
    • ATAU pilih dari daftar penelusuran sebelumnya
  4. Halaman baru akan terbuka ke halaman referensi Chrome API.

Kodenya akan terlihat seperti berikut:

Referensi API Cepat yang membuka referensi API runtime
Ekstensi Quick API yang membuka Runtime API.

Buka tips hari ini

Klik tombol Tip yang terletak di menu navigasi untuk membuka tips ekstensi.

Buka tips harian di
Ekstensi Quick API yang membuka akhir hari.

🎯 Potensi peningkatan kualitas

Berdasarkan apa yang telah Anda pelajari hari ini, cobalah untuk menyelesaikan salah satu hal berikut:

  • Jelajahi cara lain untuk menerapkan saran omnibox.
  • Buat modal kustom Anda sendiri untuk menampilkan tip ekstensi.
  • Membuka halaman tambahan ke halaman API referensi Ekstensi Web MDN.

Teruslah berkembang!

Selamat, Anda telah menyelesaikan tutorial ini 🎉. Lanjutkan untuk meningkatkan keterampilan Anda dengan menyelesaikan tutorial pemula lainnya:

Perluasan Yang akan Anda pelajari
Waktu baca Untuk menyisipkan elemen pada kumpulan halaman tertentu secara otomatis.
Pengelola Tab Untuk membuat pop-up yang mengelola tab browser.
Mode Fokus Untuk menjalankan kode di halaman saat ini setelah mengklik tindakan ekstensi.

Jelajahi lebih jauh

Untuk melanjutkan jalur pembelajaran pekerja layanan ekstensi, sebaiknya baca artikel berikut: