Menangani peristiwa dengan pekerja layanan

Tutorial yang membahas konsep service worker ekstensi

Ringkasan

Tutorial ini memberikan pengantar service worker Ekstensi Chrome. Sebagai bagian dari Anda akan membangun ekstensi yang memungkinkan pengguna membuka referensi Chrome API dengan cepat laman menggunakan omnibox. Anda akan mempelajari cara:

  • Daftarkan pekerja layanan dan impor modul.
  • Lakukan 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 Extensions 101 dan Hello World untuk pengantar tentang pengembangan ekstensif.

Membangun ekstensi

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

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. Anda tidak perlu memanggil navigator.serviceWorker.register(), seperti di halaman web.

Buat folder images lalu download ikon ke dalamnya.

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

Langkah 2: Impor beberapa modul service worker

Pekerja layanan kami menerapkan dua fitur. Agar pemeliharaannya lebih baik, kami akan menerapkan setiap fitur dalam modul terpisah. Pertama-tama, 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 di pekerja layanan.

Opsional: Melakukan debug pada pekerja layanan

Saya akan menjelaskan cara menemukan log pekerja layanan dan mengetahui kapan service worker 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 "pekerja layanan (tidak aktif)" {i>link<i} untuk memeriksanya. Animasi berikut menunjukkan hal tersebut.

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

Sekarang, uraikan ekstensi untuk mengetahui lokasi error. Salah satu cara untuk melakukannya adalah dengan menghapus ".js" dari impor './sw-omnibox.js' dalam 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 Melakukan debug ekstensi untuk mengetahui cara lainnya 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 jangka pendek; mereka dihentikan berulang kali di sepanjang sesi {i>browser<i} 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 acara Anda

Semua pemroses peristiwa harus terdaftar secara statis dalam cakupan global pekerja layanan. Dengan kata lain, pemroses peristiwa tidak boleh ditempatkan 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 kami harus mendeklarasikan pemicu kata kunci omnibox di 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 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() menggunakan masukan omnibox dan menyimpannya ke storage.local. Dengan cara ini, istilah penelusuran terbaru dapat digunakan nanti 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 operasi tertunda atau berkala tugas klasifikasi. Namun, API ini bisa gagal karena penjadwal akan membatalkan timer saat atau worker diberhentikan. Sebagai gantinya, ekstensi dapat menggunakan chrome.alarms API.

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

manifest.json:

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

Ekstensi akan mengambil semua tips, memilih satu secara acak, dan menyimpannya ke penyimpanan. Kita 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 belum.

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 tips hari itu. Klien mengirim pesan untuk meminta tip hari ini dari pekerja layanan.

Mulailah dengan mendeklarasikan skrip konten dalam manifes, lalu tambahkan 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 mengirim pesan ke pekerja layanan yang meminta tip. Kemudian, tambahkan tombol yang akan membuka pop-up 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 berisi 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 apakah kode berfungsi

Pastikan struktur file project Anda terlihat seperti berikut:

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

Memuat ekstensi Anda secara lokal

Untuk memuat ekstensi yang belum dipaketkan dalam mode developer, ikuti langkah-langkah dalam 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 API Chrome.

Kodenya akan terlihat seperti berikut:

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

Buka tips hari ini

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

Buka tips harian dalam
Ekstensi API cepat yang membuka tips hari ini.

🎯 Potensi peningkatan

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

  • Pelajari cara lain untuk menerapkan saran omnibox.
  • Buat modal kustom Anda sendiri untuk menampilkan tips ekstensi.
  • Buka halaman tambahan ke halaman API referensi Ekstensi Web MDN.

Teruslah membangun!

Selamat, Anda telah menyelesaikan tutorial ini 🎉. Terus tingkatkan keterampilanmu dengan menyelesaikan tutorial pemula:

Perluasan Yang akan Anda pelajari
Waktu membaca 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 Anda, sebaiknya jelajahi artikel berikut: