Best Practices for State Management in MV3?

407 views
Skip to first unread message

Anthony Liu

unread,
Jun 2, 2023, 11:15:13 AM6/2/23
to Chromium Extensions
Hi all,

This is a request for comment.

I'm working on an extension that loads a sidebar into a user's tabs using a content script, and I'm trying to understand best practices for how to make sure the state is consistent across all those tabs' content scripts.

For example, we have a series of checkboxes in our sidebar. Each time a user toggles a checkbox, we save the new setting into chrome.storage.local, and we want that change to automatically propagate to the other tabs' content scripts.

We are currently doing this using the chrome.storage.onChanged event to detect changes to stored values, and automatically propagate those changes through to the UI. 

However, I'm concerned about race conditions for complex cases (e.g., if we want to change an attribute of an object saved to local storage), and am wondering if there is a framework that provides a more general best practice.

From what I can tell, it seems like there could be two approaches:
  1. Create a dedicated background script that handles all updates to state. When we want to update state in a content script, the content scripts send a message to the background script, which handles the state update and then broadcasts the results back to the content scripts (either via a message event or a storage onChanged event). Consistency then comes from the fact that messages are handled in the order they are received, so we can guarantee some "atomicity" for the steps executed in response to each message.
  2. Introduce locks to our use of the chrome.storage APIs.
Is one of these approaches preferred? Are there other approaches?

From initial research, I found the webext-redux extension implementing an approach in the spirit of (1) but it's no longer maintained (nor are it's forks); for (2) I found many proposals / snippets describing locks, but no maintained or widely-used packages - and I also found this message that suggested that trying to build a locking system around chrome.storage was a flawed approach.

Thank you for any thoughts in advance,
Tony

wOxxOm

unread,
Jun 2, 2023, 1:03:50 PM6/2/23
to Chromium Extensions, Anthony Liu
Can you use the new sidePanel API which is designed specifically for this purpose? It's an extension page that survives tab navigation.

As for chrome.storage.onChanged, its broadcast may be slow for big updates i.e. when the object is big and when this listener is present in many web_accessible_resources iframes (if that's what you use).

As for the locks, there's a buit-in asynchronous API navigator.locks.

Assuming you use web_accessible_resources iframes, you can utilize the fact they all run in the same physical thread, so you can propagate the changes synchronously:

// iframe.js
window.handleGlobalMessage = msg => {
  msg = JSON.parse(msg);
  // process it
};

function propagate(msg) {
  msg = JSON.stringify(msg); // this is to ensure the prototype chain of the objects inside will belong to the target `window` and not to the source
  for (const v of chrome.extension.getViews()) {
    if (v.location.pathname === '/iframe.html') {
      v.handleGlobalMessage(msg);
    }
  }
}

wOxxOm

unread,
Jun 3, 2023, 1:21:08 AM6/3/23
to Chromium Extensions, wOxxOm, Anthony Liu
Correction: the slowness of chrome.storage.onChanged broadcast doesn't depend on web_accessible_resources iframes, it depends on the amount of contexts (tabs, frames) that listen to chrome.storage.onChanged as well as complexity of the data.

JM Lambert addeective

unread,
Jun 6, 2023, 11:38:12 AM6/6/23
to Chromium Extensions, wOxxOm, Anthony Liu
as of now sidePanel API is available only in Canary ... 

JM Lambert addeective

unread,
Jun 6, 2023, 11:47:25 AM6/6/23
to Chromium Extensions, JM Lambert addeective, wOxxOm, Anthony Liu
apologize,  just realized it landed in 114
Reply all
Reply to author
Forward
0 new messages