Synchronize Chrome Extensions state
How to use custom events to sync state between Chrome Extension instances
Monday, March 6, 2023
Introduction
This is a continuation of the previous article about creating a Chrome Extension using Svelte and Tailwind.
The problem
When an action is performed in one instance of the plugin, the data is not synced automatically. For example, if the user updates the count in one tab, the other tabs' content does not automatically react to changes.
Project setup
Clone the repo from the previous blog
The easiest way is to use degit.
1
Install dependencies and run the applicaiton
123
Handling Event Communication
This article will focus on using custom events to allow plugin communication. Check the api documentation to learn more about handling other events.
To create our custom events, we can use the chrome.runtime API. The runtime API provides a way to send messages between different parts of the extension.
Here are the steps that we can follow when creating custom events:
- Trigger an event (REQUIRED)
- Add event listener (REQUIRED)
- Handle the response from listeners
- Handle connection error
- Handle disconnection
1. Trigger an event
This step includes two changes. First, we need to change the function declaration to an async/await
syntax so it will be easier to read later on. Second, we need to dispatch a message with some payload.
The payload could be anything. In this example, I added a
type
property to the payload to identify the event in the event listener.
src/components/Counter.svelte12345678-9-10-11-12-13-14-15-16-17+18+19+20+21+22+23+24+25+26+27+28
2. Add an event listener
Since we are using Svelte, we can use the onMount
hook to add the listener.
src/components/Counter.svelte12+3+4567+8+9+10+11+12+13+14+15+161718192021222324252627282930
After adding the listener, we can see that the count is updated in all tabs.
It is easy verify that it will also work in the popup because we are using the same component.
3. Handle the response from listeners
In the event handler, we can call a sendResponse
function with the payload that we want to send back to the sender. In this example, I'm sending back the change in the count value.
The sendMessage
function returns a promise. We can use the await
keyword to get the response from the listener. In this example, I'm simply appending the response to the message;
src/components/Counter.svelte123+456789101112-13+14+1516171819
The response is now at the end of the success message.
4. Handle connection error
In case we only have one instance of the plugin running, the sendMessage
function will throw an error. Also, the success message Updated!
will always be visible because the code to hide the message will not be reached.
We can handle the error by wrapping the sendMessage
in a try/catch
block.
src/components/Counter.svelte12345-6-7+8+9+10+11+12+13+1415161718
Side note: Handle connection error with callback
If you are using a callback for whatever reason, you need to explicitly check for the error.
src/components/Counter.svelte12345678910111213141516171819202122
Now, the error is handled properly, and the code to hide the message continues to execute.
5. Unsubscribe from the listener
Sometimes, we need to free up resources. In this case, we can use the onDestroy
hook to remove the listener.
src/components/Counter.svelte1234567
An alternative is to return a function from the onMount
hook. This function will be called when the component is destroyed.
src/components/Counter.svelte12345+6+7+8+9
To simplify the demo of removing the listener, I'm removing the listener after 4 seconds the component is mounted.
src/components/Counter.svelte1234+5+6+7+89101112
The other tabs will stop listening count_changed
event, and there will be an error because no one is listening.
Repository
Check the source code here
What's next
- [ ] Add a content script
- [ ] Add a background script
- [ ] Add a dev tools page
- [ ] Deploying the extension