fix: bundle the content script to stop 'Unsafe attempt to load URL' errors

Dynamic import() of extension modules from a content script makes Chrome log
'Unsafe attempt to load URL chrome-extension://...' on YouTube pages, which fills
the extension's error list even though the modules load (HTTP 200). The content
script is now one classic file built by 'npm run build'; web_accessible_resources
is no longer needed and is removed.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
IgorVolochay
2026-10-25 12:25:06 +03:00
co-authored by Claude Sonnet 5.5
parent 38dabd9fa2
commit b137776381
9 changed files with 461 additions and 61 deletions
@@ -18,7 +18,7 @@
| Хранение | IndexedDB в браузере, экспорт в JSON и CSV из popup |
| Страницы | Главная, страница просмотра (боковые карточки), поиск, страница канала |
| Языки интерфейса | Русский и английский |
| Сборка | Нет. Чистый JS, ES-модули, загрузка как «распакованное расширение» |
| Сборка | Только для content script: `npm run build` склеивает `src/content/main.js` и его модули в один обычный файл `src/content.js` (он закоммичен, тест следит, чтобы он не отставал). Причина: динамический `import()` в content script оставляет в `chrome://extensions` ошибки «Unsafe attempt to load URL chrome-extension://…», хотя модули грузятся. Остальной код без сборки: чистый JS, ES-модули, загрузка как «распакованное расширение» |
## Откуда берётся каждое поле
@@ -38,7 +38,8 @@
| Часть | Файл | Ответственность |
|---|---|---|
| Content script | `src/content.js` | Наблюдает за DOM на `youtube.com`, разбирает карточки, отправляет в background только карточки, где VidIQ уже вывел score, и только когда данные изменились |
| Content script | `src/content/main.js` → `src/content.js` | Наблюдает за DOM на `youtube.com`, разбирает карточки, отправляет в background только карточки, где VidIQ уже вывел score, и только когда данные изменились. В манифесте подключён собранный `src/content.js`, исходник — `src/content/main.js` |
| Сборка content script | `tools/build-content.js` | Склеивает исходник и импортируемые модули в один обычный скрипт (поддерживает только однострочные `import` и `export` перед `const/let/function/class`, имена верхнего уровня должны быть уникальны) |
| Service worker | `src/background.js` | Принимает карточки, подтягивает настройки и ранее сохранённые записи, пишет результат в IndexedDB. Записи обрабатываются строго по очереди |
| Разбор карточки | `src/lib/card.js` | `scrapeCard(card, link, context)`: достаёт поля из DOM-элемента карточки |
| Данные VidIQ | `src/lib/vidiq.js` | Селекторы VidIQ, `outlierScoreFromHref`, `parseVidiqScore`, `readVidiqData` |
@@ -101,6 +102,7 @@ CSV содержит эти же поля в том же порядке.
## Тестирование
- **Автотесты** на встроенном `node:test`, без зависимостей: `numbers.js`, `vidiq.js` (на подставных объектах), `record.js`, `video-id.js`, `export.js`, `storage.js`.
- **Тест сборки** (`test/bundle.test.js`): сборщик на временных файлах, проверка, что закоммиченный `src/content.js` совпадает со свежей сборкой, что в нём нет `import()` и что в манифесте нет `web_accessible_resources`.
- **Тест разбора карточки в Chrome** (`test/card.dom.test.js`): запускает headless Chrome, загружает фикстуры и проверяет `scrapeCard`. Фикстуры: настоящая карточка с VidIQ с главной, плюс упрощённые карточки поиска и боковой панели. Если Chrome не найден, тест пропускается.
- **Сквозная проверка в Chrome** (не входит в репозиторий): живой YouTube с подмешанным в карточки блоком VidIQ, проход через content script, background, IndexedDB и popup.