Search code examples
javascriptgoogle-chrome-extensionchrome-extension-manifest-v3web-extension

Should a MV3 extension use chrome.runtime.sendMessage() or serviceWorker.controller.postMessage() for messaging?


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.


Solution

  • Data types

    • 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.

    Targeting

    • Service Worker messaging opens one directional connection.
    • Service Worker messaging doesn't have a concept of simple messaging (sending a request and receiving a response), so to properly handle asynchronously overlapped messages you'll need to implement your own queuing/ordering system.
    • Service Worker messaging doesn't work with a content script; only a 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.