Messages only received after page refresh
smeijer opened this issue · 8 comments
Hi,
I'm upgrading testing-playground to manifest v3, and moving from crx-bridge to webext-bridge. I've got things almost working, but one weird thing is bugging me.
Messages only seem to be received after an initial page refresh. So when I'd open a webpage, and open devtools, messages are sent, but not received. I confirm this with:
// devtools.js
import { sendMessage } from 'webext-bridge/devtools';
console.log('devtools loaded');
setInterval(() => {
console.log('ping');
sendMessage('PING', 'PONG', 'content-script');
}, 1_000);
// content-script.js
import { onMessage } from 'webext-bridge/content-script';
console.log('content script loaded');
onMessage('PING', () => {
console.log('pong');
});
The loaded
statements are logged, the ping
is logged, but the pong
never is. When I refresh the window with devtools open, the ping starts coming in and pong
is logged as well.
Maybe related, but not sure, when I'd switch the direction, and send a PING fromcontent-script
to devtools
, I get the error: No handler registered in 'devtools' to accept messages with id 'PING'
For context, I've also setup window messaging, but didn't seem to be relevant for this case.
Any idea what's going on?
Hi @smeijer can you please confirm how many content scripts are being loaded into the page by your extension that also have the webext-bridge/content-script
import?
Hi @zikaari ,
I have 3 content-scripts in total. Only one imports webext-bridge/content-script
.
-
A single content-script with world "isolated", with contents: (that's the whole file)
// content-script/content-script.js import { allowWindowMessaging } from 'webext-bridge/content-script'; allowWindowMessaging('com.testing-playground.devtools');
-
I also inject a content-script on world "MAIN", with contents:
// content-script/window-script.js import { sendMessage, onMessage, setNamespace } from 'webext-bridge/window'; setNamespace('com.testing-playground.devtools'); // truncated
-
I inject a content-script on world MAIN that adds some methods to
window
. It does not includewebext-bridge
I load all those scripts via the manifest:
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content-script/content-script.js"],
"run_at": "document_start"
},
{
"matches": ["<all_urls>"],
"js": ["content-script/window-script.js"],
"run_at": "document_start",
"world": "MAIN"
},
{
"matches": ["<all_urls>"],
"js": ["window/testing-library.js"],
"run_at": "document_start",
"world": "MAIN"
}
]
For full disclosure, I also have a background script (full contents):
// background.js
import 'webext-bridge/background';
And I need to communicate between content-script/window-script.js
&& devtools. Which again, works after page refresh, but not before 🤷♂️
I have a similar problem, also when I open a new tab. Also only fixed when I do a full page load. In my case I'm trying to send a message from my background script to the content script in the new tab.
Then as I type in the omnibox it autocompletes a page and prerenders it. My content script is injected and starts working just fine. But then when my background script detects that this new tab is the "active" one now and tries to send it a message, the content script never receives the message.
It seems related to this Stack Overflow article - where Chrome is automatically disconnecting the port for the content scripts of prerendered pages once they transition to their "active" lifecycle stage: https://stackoverflow.com/questions/76841137/in-chrome-extension-content-script-does-not-receive-message-from-background-on
The author of that problem solved the problem by detecting the disconnect and automatically reconnecting, queueing up and finally sending any unsent messages once reconnected.
Folks, I apologize for delayed response. Unfortunately I no longer maintain this project due to lack of resources. @smeijer would you be willing to take on this project since your project heavily depends on it?
No worries. I ended up solving by removing this package as a dependency and just writing my own simple messaging utility functions. I didn't dig in too deeply but pretty sure the problem is in the code that generates a unique key to identify the tab. Guessing that when a page is pre-rendered (when typing in a new tab) that key is different then when it transitions to active, and then the message is aborted due to key mismatch.
Something like this, where you just use the native events.
export async function sendMessageToTab(tabId: number, type: string, payload: unknown) {
return (await chrome.tabs
.sendMessage(tabId, {
to: "content",
type,
payload
})
);
}