The Chrome docs mention chrome.runtime.sendMessage
and chrome.runtime.onMessage
:
const response = await chrome.runtime.sendMessage({greeting: "hello"});
chrome.runtime.onMessage(messageHandler)
To communicate between a service worker and a content script.
However I already have messaging working within my Manifest V3 extension, between my service worker and a popup, using a different API.
In my service worker:
self.addEventListener("message", (event) => {
handleMessage(event.data);
});
and in my popup:
const SERVICE_WORKER = globalThis?.navigator?.serviceWorker || null;
SERVICE_WORKER.controller.postMessage({
topic: "getSecretKey",
});
Which of chrome.runtime.sendMessage()
and serviceWorker.controller.postMessage()
is preferable for messaging between extension components (service workers, popups, and content scripts)?
Do they have similar use cases or different limits?
Some investigation seems to be chrome.runtime.sendMessage()
is designed for messaging specifically for extensions, whereas serviceWorker.controller.postMessage()
is for general purpose webapps with service workers. But I suspect there may be more to it.
Service Worker messaging uses the structured clone algorithm which allows more data types e.g. ArrayBuffer, Blob/File, DataView, Date, Error, ImageBitmap, ImageData, Map, RegExp, Set, TypedArray, and the transferable data parameter in postMessage()
.
chrome
messaging only allows JSON-compatible types in Chrome (null, boolean, number, string, Object/Array that recursively consists of these types); Firefox also supports the clonable types listed above.
chrome-extension://
context (page or frame or worker) can use it.chrome.tabs.sendMessage
sends to all frames of the tab unless you specify frameId
in the options parameter.chrome.runtime.sendMessage
broadcasts to all chrome-extension:// contexts i.e. the background script, the popup(s), the options page, all extension tabs, all iframes that point to an html file from web_accessible_resources.P.S. No need for ?.
because SW is always usable in a context from its own origin, i.e. you can just use navigator.serviceWorker.controller
.