When the extension runtime is reloaded, which happens in any of the following cases
- You've called
chrome.runtime.reload()
.
- You've clicked on Reload extension at
chrome://extensions/
.
- The extension was updated.
then the most extension API methods in the content script cease to work (including chrome.runtime.sendMessage
which causes the error in the question). There are two ways to work around this problem.
Option 1: Fall back to contentscript-only functionality
If your extension can function perfectly without a background page, then this could be an acceptable solution. E.g. if your content script does nothing else besides modifying the DOM and/or performing cross-origin requests.
I'm using the following snippet in one of my extensions to detect whether the runtime is still valid before invoking any Chrome extension API from my content script.
// It turns out that getManifest() returns undefined when the runtime has been
// reload through chrome.runtime.reload() or after an update.
function isValidChromeRuntime() {
// It turns out that chrome.runtime.getManifest() returns undefined when the
// runtime has been reloaded.
// Note: If this detection method ever fails, try to send a message using
// chrome.runtime.sendMessage. It will throw an error upon failure.
return chrome.runtime && !!chrome.runtime.getManifest();
}
// E.g.
if (isValidChromeRuntime()) {
chrome.runtime.sendMessage( ... );
} else {
// Fall back to contentscript-only behavior
}
Option 2: Unload the previous content script on content script insertion
When a connection with the background page is important to your content script, then you have to implement a proper unloading routine, and set up some events to unload the previous content script when the content script is inserted back via chrome.tabs.executeScript
.
// Content script
function main() {
// Set up content script
}
function destructor() {
// Destruction is needed only once
document.removeEventListener(destructionEvent, destructor);
// Tear down content script: Unbind events, clear timers, restore DOM, etc.
}
var destructionEvent = 'destructmyextension_' + chrome.runtime.id;
// Unload previous content script if needed
document.dispatchEvent(new CustomEvent(destructionEvent));
document.addEventListener(destructionEvent, destructor);
main();
Note that any page that knows the name of the event can trigger destruction of your content script. This is unavoidable, because after the extension runtime is destroyed, there are no proper ways to securely communicate with the extension any more.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…