Search code examples
google-chrome-extension

How to keep a chrome extension in sync in multiple tabs


I'm trying to create a chrome extension that will be available on multiple tabs and wondering what the best way is to do this.

For simplicity, let's say the extension just displays a number and when that number changes in one tab, it must change in all tabs.

Have looked around and can't find information on things like:

  • What runs first - background or content script?
  • Should I use a long lived connection or single shot messages?
  • Is it best to create a long lived connection from the content or from the background?
  • Is it best to use storage and storage change events instead of messages?
  • Should I maintain separate ports for each content script or use one along with disconnect?

Those might be the wrong questions to ask as I may be going about this the wrong way.

Can somebody point me to best practice please.


Solution

  • Any of these questions can have more than answer so TL;DR / "best practice" is to keep it simple, not overcomplicate, at least at first, and if it's good enough then stop right there. Whether it's good enough performance-wise can be measured using any JS timing API or in devtools timeline profiler.

    What runs first - background or content script?

    In Chrome it's tricky: during browser startup if the browser option is enabled to restore the previous session (or to open a web page at start) then the content scripts of the active tab will load first, then the background script, then the other tabs' content scripts. In case the browser already runs, it depends on whether the background script is persistent or not: a persistent one has started just once when the user profile was initialized, a non-persistent runs only if there are API events or if it wasn't yet terminated from the previous API event.

    In Chrome the background script that was declared with "persistent": false will start only when necessary, on an API event for which you added a listener, then terminate after 15 seconds of inactivity. In ManifestV3 the service worker is used for the background script so the timeout is 30 seconds.

    In FF the background script can only be persistent and it always runs first.

    Should I use a long lived connection or single shot messages?

    Single message is sufficient in 99.999% of cases. Long-lived connection are only truly necessary in a few rare cases like a) if you send dozens or more messages per second to each tab, b) if you need to track disconnect event manually, c) some other rare things I don't remember right now.

    Is it best to create a long lived connection from the content or from the background?

    From content script, otherwise you would need to guess whether the tab already ran your content script (if you do it too early then it will be ignored) or wait for its 'DOMContentLoaded' event, but that may be too late in case you want to handle the early stages of page load process.

    Is it best to use storage and storage change events instead of messages?

    Depends. For example, in some simple cases the onChanged event would allow you to get rid of the background script altogether. If most of the changes in storage are related to the content script's behavior then such an event would make a lot of sense, but if you modify the storage a lot for unrelated stuff then such an event would be triggered in vain in every tab where the content script runs.

    Should I maintain separate ports for each content script or use one along with disconnect?

    Each port will be inherently different because there's no single content script: each tab/frame runs its own instance of the content script. Just like an instance of the same jquery.js would be used by every of 10 tabs that load it from the same URL.