Chrome扩展程序:如何在chrom扩展程序更新后删除孤立脚本
我有一个带有扩展页面的chrome扩展程序,该扩展程序通过简单的一次性请求将一个布尔变量传递到我的内容页面.然后,内容页面将根据从弹出页面传递的布尔变量的状态执行某些操作.直到我不小心删除了扩展程序(仍处于开发人员模式,扩展程序已解压缩)并不得不重新加载它之前,它一直运行得很好.
I have a chrome extension with a popup page which passes a boolean variable to my content page via simple one-time requests. The content page would then do some action based on the status of the boolean variable passed from the popup page. This was working perfectly until I accidentally removed the extension (still in developer mode, the extension is unpacked) and had to re-load it.
这导致扩展上下文无效错误出现在弹出检查控制台中,并且网页控制台似乎验证了弹出页面和内容脚本未在通信. chrome扩展处于活动状态的网页显示以下错误: unchecked runtime.lastError:在收到响应之前,消息端口已关闭.
This caused an extension context invalidated error to appear in the popup inspection console and the webpage console seems to validate that the popup page and content script are not communicating. The webpage with the chrome extension active shows this error: Unchecked runtime.lastError: The message port closed before a response was received.
基于我已经看到的一些答案,似乎重新加载chrome扩展程序已使我的扩展程序其余部分孤立"了我原来的工作内容脚本,这导致上述未经检查的runtime.lastError:消息端口"在收到回应之前关闭."在网页控制台上出现错误.
Based on a few answers I've already seen, it seems that reloading my chrome extension has "orphaned" my original working content script from the rest of my extension, which causes the aforementioned "Unchecked runtime.lastError: The message port closed before a response was received." error on the webpage console.
我相信我不能再重新注入内容脚本,因为我的内容脚本具有DOM事件侦听器.有没有可能删除当前正在运行的孤立脚本的方法?还是有解决此问题的建议方法?
I believe that I cannot just reinject my content script again as my content script has DOM event listeners. Is there a possible way to remove the currently running orphan script? Or is there any suggested workaround to this problem?
这是我的popup.js:
Here is my popup.js:
chrome.tabs.query({'active': true, 'currentWindow': true}, function (tabs) {
chrome.tabs.sendMessage(tabs[0].id, {cTabSettings: (some boolean variable)});
});
这是我的content.js:
Here is my content.js:
// Listening for message from popup.js
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
if (request.cTabSettings === true) {
enabled = true;
} else if (request.cTabSettings === false) {
enabled = false;
}
});
// DOM listener and action
document.addEventListener('mousemove', function (e) {
// Some action
chrome.runtime.sendMessage({sender: "content", selText : "blah"}, function () {
console.log("success");
});
}, false);
我使用的是chrome开发人员模式76版.只是要改写一下,这个chrome扩展程序在我意外加载之前就可以正常工作(内容脚本与弹出窗口进行通讯).
I am using chrome developer mode version 76. Just to rephrase, this chrome extension was working (content script communicates with popup) before I accidentally reloaded it.
由于孤立的内容脚本仍可以接收DOM消息,因此,例如,可以通过window
将新的工作内容脚本中的一个发送到幻影的内容脚本中.收到消息后,您将注销所有侦听器(并使所有全局变量无效),这还将使您的旧脚本有资格进行自动垃圾收集.
Since the orphaned content script can still receive DOM messages, send one from your new working content script to the ghosted content script via window
, for example. Upon receiving the message you'll unregister all listeners (and nullify any global variables) which will also make your old script eligible for automatic garbage collection.
content.js:
content.js:
var orphanMessageId = chrome.runtime.id + 'orphanCheck';
window.dispatchEvent(new Event(orphanMessageId));
window.addEventListener(orphanMessageId, unregisterOrphan);
// register all listeners with named functions to preserve their object reference
chrome.runtime.onMessage.addListener(onMessage);
document.addEventListener('mousemove', onMouseMove);
// the popup script checks it to see if a usable instance of content script is running
window.running = true;
function unregisterOrphan() {
if (chrome.i18n) {
// someone tried to kick us out but we're not orphaned!
return;
}
window.removeEventListener(orphanMessageId, unregisterOrphan);
document.removeEventListener('mousemove', onMouseMove);
try {
// 'try' is needed to avoid an exception being thrown in some cases
chrome.runtime.onMessage.removeListener(onMessage);
} catch (e) {}
return true;
});
function onMessage(msg, sender, sendResponse) {
//...........
}
function onMouseMove(event) {
// DOM events still fire in the orphaned content script after the extension
// was disabled/removed and before it's re-enabled or re-installed
if (unregisterOrphan()) { return }
//...........
}
我假设popup.html加载 WebExtension browser
API polyfill ,因为它可以通过允许我们使用async/await语法而不是令人费解的回调地狱,生活变得更加轻松.
I'm assuming popup.html loads WebExtension browser
API polyfill because it makes life much easier by allowing us to use async/await syntax instead of the mind-boggling callback hell.
<script src="browser-polyfill.min.js"></script>
popup.js应该确保在发送消息之前已注入内容脚本:
popup.js should ensure a content script is injected before sending a message:
async function sendMessage(data) {
const [tab] = await browser.tabs.query({active: true, currentWindow: true});
if (await ensureContentScript(tab.id)) {
return await browser.tabs.sendMessage(tab.id, data);
}
}
async function ensureContentScript(tabId) {
try {
const [running] = await browser.tabs.executeScript(tabId, {
code: 'window.running === true',
});
if (!running) {
await browser.tabs.executeScript(tabId, {file: 'content.js'});
}
return true;
} catch (e) {}
}