#reactjs #webpack #google-chrome-extension
#reactjs #webpack #google-chrome-extension
Вопрос:
Здесь вопрос новичка:
На прошлой неделе я написал очень простое расширение Chrome, в котором popup.js отправляет сообщение на content.js сценарий, следующим образом (возможно, это был не лучший способ, но здесь важно то, что он сработал. Почему это важно? Потерпите меня …)
В popup.js
someButton.addEventListener('click', (event) => {
chrome.tabs.executeScript(null, {
file: 'src/content.js',
}, () => {
connect();
});
});
и более поздние версии:
function connect() {
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
const port = chrome.tabs.connect(tabs[0].id);
port.postMessage({ type: 'info', data: someValue });
})
}
В content.js
if (!chrome.runtime.onConnect.hasListeners()) {
chrome.runtime.onConnect.addListener((port) => {
port.onMessage.addListener((msg) => {
if (msg amp;amp; msg.type == "info") {
// do some stuff
}
});
});
}
Это сработало, но я считаю, что это не лучший способ. Я читал гораздо больше с прошлой недели и знаю, что считаю, что правильный путь должен быть примерно таким:
На popup.js
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
chrome.tabs.sendMessage(tabs[0].id, {
type: "info",
someValue: value
});
});
И в content.js
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
if (request.type == "info"){
sendResponse({ message: "some answer" })
}
return true;
})
Но в моей новой версии это не работает, даже если в каждом руководстве и документации указано, что это должно. Я не получаю никаких ошибок, просто функция, добавленная в прослушиватель, никогда не выполняется.
Я подозреваю, что, возможно, это может быть связано с тем, что сейчас я использую React и Webpack, и, возможно, Webpack делает что-то странное?
Фрагмент моего manifest.json
"background": {
"persistent": false,
"scripts": ["background.bundle.js"]
},
"content_scripts": [{
"matches": ["<all_urls>"],
"js": ["content.bundle.js"]
}],
Может быть, проблема в том, что я указываю содержимое и фон с помощью пакетов? Не уверен, единственное, что я знаю, это то, что, насколько я понимаю, это должно работать, а это не так.
Чего мне не хватает?
PS: Я должен добавить, что я проводил отладку и обнаружил, что файлы содержимого выполняются, и фрагмент кода, который отправляет сообщение, также был выполнен. Похоже, что addListener не добавлен должным образом или по какой-то причине никогда не получал сообщение.
Ответ №1:
Когда вы объявляете content_scripts
в manifest.json, по умолчанию он выполняется между событиями DOMContentLoaded
и load
, поэтому, если вы открыли всплывающее окно на сложной странице, которая все еще загружается, сценарий содержимого для получения сообщения не будет.
Вы можете указать «run_at»: «document_start», чтобы скрипт содержимого запускался при «запуске», когда страница все еще пуста, в DOM будет только document.documentElement
для <html>
узла, не будет <head>
или <body>
.
Обратите внимание, что сценарий содержимого, объявленный в manifest.json, всегда запускается на каждой соответствующей странице, поэтому, если вашему расширению требуется сценарий содержимого только после щелчка во всплывающем окне, это будет очень, очень плохо, потому что вы тратите ресурсы 99,999% времени и фактически требуете широких разрешений хоста. В этом случае вам следует 1) удалить content_scripts
из manifest.json, 2) добавить activeTab
в «разрешения» и удалить все широкие разрешения хоста, такие как <all_urls>
или *://*/*
или http://*/*
, 3) использовать executeScript и hasListeners, как вы делали раньше.
Комментарии:
1. большое вам спасибо, как всегда, ваш ответ очень проясняет. Но, к сожалению, у меня все еще есть некоторые сомнения. Например, поскольку я использовал executeScript, я отправил имя файла, но с webpack должен использовать имя пакета? Что-то вроде
chrome.tabs.executeScript( null, { file: "content.bundle.js", }, () => { connect(); } );
2. Извините за форматирование кода, комментарии обладают меньшей гибкостью для этого
3. Не могу помочь с webpack. Это зависит от конфигурации вашего webpack, поэтому попробуйте задать новый вопрос об этом.