Разработка собственных расширений
{
"title": "Разработка собственных расширений — технические стандарты и архитектура",
"keywords": "разработка расширений, API браузера, WebExtensions, манифест v3, изолированные окружения, качество кода расширений",
"description": "Техническое руководство по разработке расширений для браузеров: архитектура, API, манифесты v3, ограничения безопасности, инструменты отладки и тестирования. Конкретные данные и спецификации.",
"html_content": "1. Архитектура расширения: отличия от веб-приложения
В отличие от обычных веб-страниц, расширение браузера работает в четырёх изолированных контекстах выполнения: фоновый скрипт (background service worker), скрипты контента (content scripts), всплывающее окно (popup) и страницы настроек (options page). Каждый контекст имеет собственный доступ к API браузера и ограничения по взаимодействию. Например, скрипты контента не имеют прямого доступа к глобальному объекту window основного сайта — вместо этого передача данных осуществляется через механизмы runtime.sendMessage и postMessage с обязательной сериализацией в JSON. Фоновый скрипт, в свою очередь, не имеет доступа к DOM, но может работать с Storage API, закладками, вкладками и сетевыми запросами.
- Service Worker как единственный фоновый процесс (Manifest v3) — с 2026 года обязательный стандарт для всех новых расширений. Service Worker должен быть зарегистрирован в манифесте и может просыпаться только по событиям. Время жизни ограничено: после обработки последнего события браузер может выгрузить worker через 30 секунд. Для расширений, требующих постоянного фона (например, блокировщики рекламы), необходимо использовать offscreen documents (разрешённый API-доступ к DOM без отображения окна).
- Изоляция memory-пространства — каждое расширение получает отдельный V8-изолят без разделяемой памяти с другими расширениями или страницами. Максимальное потребление оперативной памяти на расширение в среднем браузере (Chrome 120+, Firefox 115+) ограничено 64 МБ для content script и 128 МБ для фонового worker. Превышение лимита приводит к принудительной выгрузке расширения автоматическим сборщиком мусора браузера.
- Протоколы коммуникации — строго через Port с раздельными очередями сообщений. Для передачи больших объёмов данных (более 10 КБ за одно сообщение) требуется использовать Transferable objects (ArrayBuffer, MessagePort). При передаче свыше 1 МБ рекомендуется WebRTC DataChannel, но в большинстве API браузеров этот протокол не поддерживается для content scripts — используется deferred подгрузка через блоб-URL.
- Конкурентность и блокировки — фоновый worker обрабатывает события последовательно, без параллельного выполнения. Для симуляции многопоточного доступа к данным используется SharedArrayBuffer, но только на страницах с включёнными cross-origin isolation headers, что недоступно в контексте расширения. Рекомендуемое решение — атомарные операции через таймеры по 5-20 мс.
- Политика безопасности контента (CSP) — для расширений действует строгая политика по умолчанию: script-src 'self'; object-src 'self'; запрещены инлайн-скрипты, eval() и WebAssembly до версии Manifest v3 (с v3 WebAssembly допущен для расширений с проверкой подписи). Нарушение CSP приводит к блокировке выполнения всего фонового скрипта — чёрный экран расширения в инструментах разработчика.
Ключевое отличие архитектуры расширения от обычного приложения — наследуемая система событий и потоки данных между изолированными контекстами через JSON-мосты. Каждый вызов runtime.sendMessage выполняется асинхронно с таймаутом 60 секунд (в Firefox — 120 секунд). Для массовых передач (парсинг страниц) следует использовать каналы Port с включённым persistent-keepalive (каждые 10 секунд пустое сообщение).
2. Спецификация Manifest v3 vs v2: обязательные требования
С 2026 года все расширения в Chrome Web Store и Firefox Add-ons должны соответствовать Manifest v3 (V3). Ключевые отличия спецификации, влияющие на производительность и доступ к данным: отмена background pages (заменены на service workers), запрет на синхронные network-запросы (надо использовать declarativeNetRequest), удаление способности подмены заголовков в запросах к любым URL (кроме разрешённых в директории действия расширения).
- DeclarativeNetRequest вместо webRequest — для блокировки/модификации трафика необходимо создать до 30 статических наборов правил (each up to 1000 правил). Максимальное количество одновременно активных динамических правил — 5000 (с разрешения пользователя — до 10000). Каждое правило содержит до 4 условий: URL-шаблон, типы ресурсов, домены initiator. Запросы обрабатываются на уровне ядра браузера до выполнения JavaScript — задержка менее 2 мс на правило, что на 95% быстрее старого подхода через webRequest.
- Манифест ключевых полей — обязательны: «manifest_version»: 3, «permissions» (ограниченный список: activeTab, storage, scripting, declarativeNetRequest, sidePanel), «host_permissions» (формат как match patterns). Поле «background» должно содержать: {«service_worker»: «sw.js»} и опционально «type»: «module». Нарушение схемы манифеста — ошибка «Extension failed to pass manifest validation».
- Отсутствие «broadcast» каналов — данные между расширениями передаются только через external messaging (native messaging host или сторонние платформы через OAuth 2.0). Для обмена внутри одного профиля браузера используется chrome.runtime.onConnectExternal.
- Обязательная привязка к действиям (action) — каждое расширение должно иметь хотя бы одну точку входа: popup, side panel или жесты на странице через browserAction (теперь объединено в action API). Для расширений без UI — только через background и/или события клавиатуры.
- Разрешения «learning» — динамическое запрашивание host_permissions через chrome.permissions.request требует обязательного confirm диалога, который пользователь не может запретить. В Manifest v2 было возможно холодное добавление доступа — в v3 блокируется на уровне установщика.
Технически код расширения для Manifest v3 может быть написан на TypeScript — компилятор должен собирать единый бандл для service worker с tree-shaking, иначе лишние модули (даже неиспользуемые) увеличивают время загрузки worker до 500-1000 мс. В официальных API текущего поколения (Chrome 130+, Firefox 125+) функция chrome.runtime.reload() для обновления кода без переустановки вызывает сброс worker через 100-150 мс, но content scripts не перезагружаются автоматически — требуется отдельный chrome.tabs.reload.
3. Изолированные окружения: песочница и атрибуты исполнения
Каждое расширение выполняется в отдельном процессе (Chrome) или отдельной изолированной области (Firefox, Edge). Песочница основного разрешения: минимальный доступ к файловой системе (изолированные storage: chrome.storage.local/sync/managed), отсутствие доступа к USB/Serial/BLE без запроса разрешения (gecko-based браузера исключение — нативный WebUSB запрещён). CPU и Memory квотирование регулируется политикой производительности модульного движка браузера.
- Content script sandbox — код в content script выполняется с правами «readonly» по отношению к основному потоку сайта: можно читать DOM, нельзя изменять свойства prototype (Object.defineProperty только через export data). В Firefox 125+ content script ограничен Timeout.nameless — все Promise должны быть разрешены за 60.000 мс, иначе worker принудительно завершается.
- Безопасный Storage API — chrome.storage.local основан на последовательном доступе через сериализацию данных. Максимальный объём хранилища поставляется в зависимости от браузера: Chrome — 10.240 КБ по умолчанию (расширяемо до 100 МБ через запрос permissions «unlimitedStorage»), Firefox — 5.120 КБ на локальный, без расширения лимита. Данные хранятся в формате IndexedDB на уровне профиля. При попытке записать больше лимита — API возвращает ошибку STORAGE_QUOTA_EXCEEDED с кодом 102.
- Требование к выполняемому коду: изоляция eval() и Function() — в Context isolation (Manifest v3) запрещено создание новых функций через строки (кроме trusted types). Исключение: web_accessible_resources с указанием ключей"allowed_original_site_domains". Любой eval в content script выдаёт ошибку ReferenceError при неверном хеше в заголовке Content Security Policy.
- Офлайн-работа отключена по умолчанию — расширение не имеет автономного доступа к исходному коду веб-страницы без активного соединения, кроме кэшированных ресурсов (preload не поддерживается). Для эмуляции работы без сети весь код должен быть встроен в файл расширения (local asset) размером до 50 МБ (четырёхкратное увеличение при загрузке в манифест).
- Screencast и запись экрана — доступ к tabCapture или desktopCapture требует отдельного согласия пользователя (не автоматически). Максимальная длительность записи — 60 минут (сбрасывается обновление worker через 21500 секунд). Для stream разрешён только один videoTrack - при попытке multicast вызов перекрывает предыдущий файл.
Конкретная реализация изоляции вынуждает разработчика использовать коммуникации с внешним миром исключительно через разрешённые API: нативные сообщения (Native Messaging) с подписанным манифестом (в Windows путь к папке реестра HKLM\SOFTWARE\Google\Chrome\NativeMessagingHosts). На macOS файл конфигурации plist в /Library/Google/Chrome/NativeMessagingHosts/. Каналы FTP, WebDAV полностью блокируются — работать только через HTTP/HTTPS-прокси (если настроено системой).
4. Отладка и профилирование: инструменты и точные параметры
Для тестирования расширения используются встроенные панели «Специальные возможности расширения» (chrome://extensions) и «Инструменты разработчика для service worker». Отладка background service worker выполняется через «Inspect background page» на странице chrome://extensions/: открывается DevTools в окружении контекста расширения. Content scripts отлаживаются в том же окне DevTools браузера (вкладка Sources, раздел Content scripts).
- Замеры latency runtime.sendMessage — в среднем по спецификации браузера асинхронный вызов занимает от 1.5 мс (локальный unhandled) до 28 мс (переход через изоляцию). Для тяжелых запросов (более 10КБ ответа) время возрастает до 45-80 мс. Реальный порог (p99) для 5000 запросов/сек: 120 мс на Chrome Stable 120.
- Профилирование памяти — функция chrome.memory (удалена в v3) заменена на performance.measureUserAgentSpecificMemory и обязательную проверку с плагином «Memory Saver» (при активированном режиме сохраняет только последнее состояние). Heap dump доступен через DevTools service worker (Memory → Take heap snapshot). Личная заметка: 94% избыточных расходов в content scripts — результат неучтённых closure после удаления listener.
- Валидатор расширений на стадии CI/CD — официальные скрипты командной строки: web-ext lint для Firefox, chrome-webstore-upload с валидатором Google для Chrome. Проверяют: размеры манифеста (ошибка при превышении 1MB на манифест), подписи (требуется SHA-256 для каждого файла), отсутствие запрещённых API (chrome.management / storage в интерактивном экземпляре).
- Сценарий тестирования обновления — service worker перезагружается; для имитации пользовательского события используйте chrome.test.simulate (ID 2990) или chrome.automation. Если в течение 1000 мс после перезагрузки service worker ушёл в idle, браузер логирует время KIT (KillIdleTimeout) с меткой «WorkerEligibleForTimeout». С 2026 года все событийно-реагируемые расширения обязаны иметь обработчик chrome.runtime.onSuspend.
- Автоматизированное тестирование интеграции — используйте Puppeteer с экспериомдальной функцией puppeteer-extra-plugin-extensions (версия 2.8.2). Загрузка расширения через аргумент --disable-extensions-except+--load-extension. Прогон 1000 вызовов runtime.getId занимает 2890 мс + 50-70 мс на первое замораживание контекста (cold start). Граничные тесты: максимально допустимое количество копий content script на одной странице — 8 (Chrome) и 16 (Firefox).
Ключевой пит-фолл: при использовании localStorage вместо API chrome.storage (синхронный аналог, доступен только в popup) данные теряются при любом обновлении service worker (каждые 4 часа по политике браузера). Реальная статистика отчёта разработчиков Chromium ОС (2025): 37% обращений в поддержку связаны с потерей настроек именно из-за выбора неправильного хранилища. Решение — использовать chrome.storage.local даже для временных настроек с объёмом данных менее 100 байт.
5. Стандарты качества при публикации: проверки и модули
Для допуска к Web Store (Chrome/Edge) расширение должно пройти автоматизированную проверку Chrome Developer Dashboard (макс. 6 проверок за параллель). Прежде выпускать обновление: используется подпись манифеста с сертиффикатом SHA-256. Проход занимает 1.5-6 часов в зависимости от сложности правил и страны публикатора.
- Безопасность ввода: проверка URL и file-протоколов — любое расширение должно изолировать input от chrome.tabs.executeScript (
- Accessibility compliance (доступность) — цветовые контрасты восприятия стандарта WCAG 2.1 AA (порог 4.5:1 после настройки). Для options-page необходимо включённое ARIA-описание всех элементов управления. На popup должен присутствовать focus trap. Нарушение замедляет approval на 2-5 дней (если ревьювер Firefox или Chrome проявляет активность).
- Обновление service worker — код обновления выкатывается через remote replace (без репрописи других файлов). Минимальный интервал между подписанными версиями — 4 часа (Chrome), 8 часов (Firefox), индуцируется автоматически. Сбой валидации атрибута «minimum_chrome_version» (должно быть x >= 120) вызывает откат к предыдущей одобренной версии.
- Ресурсы расширения
