Короче ответ на собственный же вопрос получился приличной портянкой. Текущее решение во второй части ответа, а в первой саммари из обсуждения на stackoverflow.
В общем вот вопрос на stackoverflow под которым собралось больше всего разных решений
https://stackoverflow.com/questions/48104433/how-t...
Что я понял из этого всего:
- Самое лучшее - разобраться с Webpack и собирать код браузерного плагина через него. Возможно другой сборщик тоже прокатит, тот же Parcel.
- Можно обойтись без import/export, подключив несколько скриптов сверху вниз и используя в нижнем функции и переменные из верхних. Но мне кажется, что это не так уж и удобно для разработки. Императивный подход подобного мультиподключения для плагинов на mv2 (manifest.json v2) неудобен, т.к. надо один executeScript оборачивать другим. Декларативный чуть удобнее, но тогда надо все это лепить прямо в manifest.json, у этого тоже вижу свои минусы. Если делать плагин на mv3, там дела у императивщины лучше, т.к. вместо file в executeScript указывается массив files.
- Хак с промежуточным файлом в executeScript, который вставляет на веб-страницу уже собственно наш скрипт с бизнес-логикой (а еще в manifest.json нужно добавить скрипты в web_accessible_resources). Я попробовал, сработало, но выглядит это решение не очень изящно, а также оно было раскритиковано на stackoverflow. mv2 дает такое сделать, mv3 не пропускает столь грубый метод.
- Также возможно неплохая идея перенести расширение на manifest v3. Это и в целом правильно, и там на stackoverflow предложили вроде как неплохое решение для mv3, которое я тоже проверил - оно чуть лучше предыдущего, но все равно не очень, особенно если плагин большой.
Ну а так для удобной разработки большого плагина только вариант 1 (походу).
UPD: В итоге, после очередного перепрочтения инфы по указанной ссылке на stackoverflow, я додумался до варианта, который не иначе как мегакостылем не назовешь. Но он позволяет ограничиться одним промежуточным файлом, причем в 1 строчку, и через него подключать любое кол-во файлов, где уже свободно можно юзать импорты. А также этот способ не такой грубый, как вставка тега script напрямую на веб-страницу. В общем, мне даже понравилось.
Костыль использует 3 решения:
- Один executeScript вложенный в другой
- Использование globalThis
- Использование динамического импорта
А если конкретнее, то в background.js у меня вот что:
chrome.tabs.executeScript(tabId, { code: 'globalThis.path = "folder/your_content_script.js"'}, () => {
chrome.tabs.executeScript(tabId, { file: 'folder/middle.js' })
})
middle.js это файл в 1 строчку:
(async () => await import(chrome.runtime.getURL(globalThis.path)))()
И всё, это работает! Чтобы в background.js каждый раз не писать вложенный executeScript, я сделал функцию хелпер:
function executeImportedScript(tabId, path) {
chrome.tabs.executeScript(tabId, { code: `globalThis.path = '${path}'`}, () => {
chrome.tabs.executeScript(tabId, { file: 'folder/middle.js' })
})
}
И в нужном месте просто:
executeImportedScript(tabId, "folder/your_content_script.js")
Только в manifest.json в ключе
web_accessible_resources должны присутствовать пути ко всем контент-скриптам + пути ко всем скриптам, из которых контент-скрипты что-то импортируют. И собственно это пока единственная проблема, которую я вижу у этого способа - разбухание manifest.json и
web_accessible_resources в частности (для большого плагина).