Расширение для Chrome с ИИ: пошагово (Manifest V3)

Расширение для Chrome с ИИ по шагам: Manifest V3, content-скрипты, service worker, минимум разрешений, защита API-ключей и публикация в Chrome Web Store.

Solviera Teknoloji 7 мин чтения

Расширение для Chrome с ИИ — один из самых лёгких путей в vibe coding: расширение состоит из нескольких небольших файлов, его можно тестировать в собственном браузере без всякого сервера, а кодинг-агенты вроде Claude Code или Codex хорошо знают структуру Manifest V3. Сложность не в коде, а в выборе нужной части (content-скрипт, service worker, popup), в просьбе о минимуме разрешений и в том, чтобы никогда не класть API-ключи внутрь расширения. Статья описывает путь, которым я иду от пустой папки до Chrome Web Store.

В качестве примера сделаем небольшое, но настоящее расширение: оно пересказывает статью на текущей странице с помощью AI API. С vibe coding первую версию можно собрать за вечер; версии для публикации нужно ещё несколько правил.

Сначала узнайте части

Чтобы объяснить агенту, что вам нужно, достаточно знать четыре строительных блока расширения Chrome:

  • manifest.json: Паспорт расширения. Название, версия, какой файл что делает и каких разрешений просит расширение. Новые расширения используют Manifest V3.
  • Content-скрипт: JavaScript, который работает внутри посещаемой страницы. Он может читать текст страницы, добавлять кнопку, скрывать элемент. Напрямую обратиться к переменным JavaScript самой страницы он не может: он работает в изолированном «мире».
  • Service worker (фон): Код, который работает независимо от страниц. Он реагирует на события вроде клика по значку на панели, смены вкладок или будильников и делает сетевые запросы. Важное свойство: Chrome останавливает его в простое, поэтому всё, что лежит в глобальной переменной, может пропасть.
  • Popup и страница настроек: Небольшое окно, которое открывается по клику на значок, и отдельная страница для настроек. Обе — обычные HTML-страницы.

Эти части общаются через chrome.runtime.sendMessage и chrome.tabs.sendMessage. Когда написанное агентом «не работает», причина очень часто в том, что код выполняется не в той части, например, document пытаются использовать в service worker.

1. Подготовка и структура проекта

Вам нужны Chrome (или другой браузер на Chromium), Git, редактор кода и кодинг-агент. Для первого расширения инструмент сборки не нужен; хватит чистого JavaScript. Когда проект вырастет, фреймворки для расширений на Vite вроде WXT добавят TypeScript и автоперезагрузку, но для первой версии я бы обошёлся без лишнего слоя. Без него ошибки агента лучше видны.

mkdir page-summarizer && cd page-summarizer
git init

Затем положите в корень проекта короткий файл правил, который агент читает в каждой сессии (CLAUDE.md или AGENTS.md):

# Page Summarizer (Chrome extension)
- Manifest V3, plain JavaScript, no build step.
- Minimal permissions: activeTab, scripting, storage. No <all_urls>.
- No remote code; no eval, no remote <script>.
- No API key in the extension; requests go to our own server.
- Persistent state in chrome.storage, not in service worker globals.
- Ask before adding a permission or a package.

2. Первый промпт

В первом сообщении я прошу агента объяснить, что он собирается сделать и какие файлы создаст, а потом написать код:

Read CLAUDE.md. Build a Manifest V3 Chrome extension:
- Clicking the toolbar icon opens a popup with a "Summarize" button.
- Pressing it grabs the article text from the active tab (use activeTab +
  scripting and inject the content script only at that moment).
- The text goes to the service worker, which POSTs it to
  https://api.my-server.example/summarize.
- Show the summary in the popup; on error show a readable message.
- Keep the last 10 summaries in chrome.storage.local.
First list the files and what each one does, then create them.
Finish with step-by-step instructions to load and test it.

manifest.json, который выдаст агент, должен выглядеть примерно так:

{
  "manifest_version": 3,
  "name": "Page Summarizer",
  "version": "0.1.0",
  "description": "Summarizes the article on the current page in one click.",
  "action": { "default_popup": "popup.html" },
  "background": { "service_worker": "background.js" },
  "permissions": ["activeTab", "scripting", "storage"],
  "host_permissions": ["https://api.my-server.example/*"]
}

Здесь я проверяю список разрешений. activeTab даёт временный доступ только к текущей вкладке, когда пользователь нажимает на значок. Агенты часто добавляют "<all_urls>" или "tabs" для удобства; это показывает пользователям пугающее предупреждение и замедляет проверку в магазине.

3. Загрузка, тесты, отладка

Прежде чем идти в магазин, проверьте расширение в собственном браузере:

  1. Откройте chrome://extensions.
  2. Включите Developer mode в правом верхнем углу.
  3. Нажмите Load unpacked и выберите папку проекта.
  4. Закрепите значок на панели и попробуйте расширение на статье.

После изменения кода нажмите кнопку перезагрузки на карточке расширения в chrome://extensions. Если менялся content-скрипт, перезагрузите и страницу, на которой вы тестируете.

Три места, которые больше всего помогают при отладке:

  • Service worker: Ссылка «service worker» на карточке расширения открывает собственные DevTools. Здесь видны сетевые запросы и фоновые ошибки.
  • Popup: Когда popup открыт, щёлкните по нему правой кнопкой и выберите Inspect.
  • Content-скрипт: Логи появляются в консоли DevTools самой страницы; ваше расширение можно выбрать в выпадающем списке контекстов вверху консоли.

Если на карточке расширения есть кнопка Errors, скопируйте её содержимое как есть и передайте агенту:

I loaded the extension. Pressing "Summarize" in the popup shows this error:
[error text]
The service worker console also shows:
[log]
Explain the cause, fix it, and list what you changed in which file.

Когда вы говорите, где сломалось, на что вы нажимали и что показывает каждая консоль, агент исправляет проблему, а не гадает.

4. Хранилище: выберите правильное место

  • chrome.storage.local: Данные на этом устройстве, например история пересказов.
  • chrome.storage.sync: Синхронизируется между устройствами через профиль Chrome пользователя. Квота небольшая; используйте только для настроек.
  • chrome.storage.session: Очищается при закрытии браузера; подходит для временного состояния, которое должно пережить перезапуск service worker.

В service worker нет localStorage. Если агент пытается его использовать, по этой причине код падает. И не забудьте разрешение storage в manifest.json.

5. Не держите API-ключи в расширении

Это самая частая ошибка в расширениях, созданных с ИИ. Агент пишет «вставьте сюда ваш ключ OpenAI» и кладёт константу в background.js. Опубликованное расширение — это ZIP-файл; любой может скачать его, распаковать и прочитать ваш ключ. Минификация и обфускация этого не меняют.

Правильная структура — небольшой прокси:

  1. Расширение обращается к вашему серверу (https://api.my-server.example/summarize).
  2. Сервер хранит ключ в своём окружении и вызывает настоящий AI API.
  3. Сервер ограничивает частоту запросов (по пользователю или IP) и отклоняет слишком большие тексты.

Откройте отдельный проект для этого сервера и скажите агенту:

Write a small HTTP service: POST /summarize takes { text } in the body.
Cap the text at 20,000 characters, call the AI API with the key from an
environment variable, return { summary }. Allow CORS only for the
chrome-extension://<EXTENSION_ID> origin. Add a simple rate limit.
Never log the key. Create a .env.example file.

Идентификатор расширения показывается на chrome://extensions, когда вы загружаете его как распакованное; после публикации в магазине он может быть другим. Обновите настройку CORS перед публикацией. Если пользователи приносят свой ключ (это обычное дело для инструментов разработчика), запрашивайте его на странице настроек и храните в chrome.storage.local; свой ключ никогда не поставляйте.

В чём ИИ ошибается

  • Пишет код для Manifest V2. background.page, chrome.browserAction, постоянная фоновая страница или webRequestBlocking пришли из старых примеров. Скажите агенту: «используй эквивалент из Manifest V3».
  • Считает, что service worker работает всегда. Счётчик в глобальной переменной или setInterval через какое-то время останавливаются. Для работы по расписанию используйте chrome.alarms, а для состояния chrome.storage.
  • Просит слишком много разрешений. <all_urls>, tabs, history обычно не нужны. Попросите агента обосновать каждое разрешение одним предложением; уберите те, которые он обосновать не может.
  • Загружает удалённый код. Подключение библиотеки с CDN через <script> или использование eval в Manifest V3 не разрешены. Включите библиотеку в пакет.
  • Тянется к переменным страницы из content-скрипта. Так как он работает в изолированном мире, он не видит window.someApp; работать нужно через DOM.
  • Забывает об асинхронных ответах в сообщениях. Если слушатель onMessage отвечает асинхронно, он должен вернуть return true, иначе popup получит пустой ответ.
  • Считает, что у всех сайтов одинаковый HTML. Чтобы получить текст статьи, сначала ищите элемент article или main и разумно переходите к запасному варианту. Проверьте на трёх разных сайтах.

Безопасность

  • Секреты хранятся в .env на сервере. Никакого .env в папке расширения; он попал бы в ZIP.
  • Никогда не вставляйте API-ключи в чат. Агенту нужно имя переменной, а не ключ.
  • Читайте команды, которые запускает агент. Особенно установку пакетов и всё вроде curl … | sh.
  • Не доверяйте данным страницы. Не выводите текст, прочитанный content-скриптом, в popup через innerHTML; используйте textContent. Иначе вредоносная страница сможет внедрить код в ваше расширение.
  • Проверяйте, от кого пришло сообщение. Если сообщения извне не нужны, не добавляйте externally_connectable; если нужны, держите список разрешённых источников узким.
  • Собирайте только необходимое. Если текст страницы уходит на ваш сервер, скажите об этом прямо и не храните его там.

6. Публикация в Chrome Web Store

Публикация выглядит примерно так:

  1. Создайте аккаунт разработчика. Зарегистрируйтесь в панели разработчика Chrome Web Store; регистрация требует единоразового взноса.
  2. Упакуйте проект. Заархивируйте папку проекта в ZIP так, чтобы манифест лежал в корне. Не включайте .git, node_modules, тестовые файлы и .env.
  3. Заполните карточку. Описание, скриншоты, значки, категория.
  4. Заполните раздел о конфиденциальности. Укажите единственное назначение расширения, обоснуйте каждое разрешение и объявите, какие пользовательские данные вы собираете. Если вы собираете данные, нужен общедоступный URL политики конфиденциальности.
  5. Отправьте на проверку. Срок разный. Широкие разрешения для хостов и трудночитаемый код могут её замедлить; при отказе в письме указано, какую политику вы нарушили.

И здесь поможет агент:

I'm submitting this extension to the Chrome Web Store. For each
permission in manifest.json, write a one-sentence justification for the
store form, write the single-purpose description and list the user data
we collect. Tell me if any permission looks unnecessary. Give me a command
that builds the release ZIP without .git, .env and test files.

Для обновлений повышайте version в manifest.json. Добавление нового разрешения может отключить расширение у существующих пользователей, пока они его не одобрят, поэтому подумайте дважды, прежде чем его добавлять.

Как я делаю это в AgentVera

Расширение можно собрать с одним терминалом и браузером. AgentVera я использую, когда делаю расширение и прокси-сервер одновременно:

  • Два агента, две задачи. В рабочем пространстве я открываю агента Claude Code для расширения и агента Codex для прокси-сервера, каждого в своей папке или git worktree.
  • Проба сервера. API-клиент умеет находить конечные точки сервера по его коду; я проверяю там /summarize, прежде чем подключать её к расширению.
  • Отправка ошибок агенту. Вывод ошибок из терминала я отправляю выбранному агенту через Send to agent вместо копирования и вставки.
  • Ревью перед слиянием. Ревью кода проверяет каждый завершённый ход, а панель Git показывает diff. Лишнее разрешение или встроенный ключ обычно ловятся здесь.
  • Учёт токенов. Каждая панель показывает размер контекста в реальном времени; маленькому расширению не нужна раздутая сессия.

Загрузить расширение в Chrome и попробовать его по-прежнему должны вы; AgentVera этого за вас не делает.

Подводим итоги

Чтобы создать расширение для Chrome с ИИ, изучите части (манифест, content-скрипт, service worker, popup), дайте агенту письменные правила, начните с минимума разрешений, загрузите расширение как распакованное и отлаживайте из нужной консоли, а API-ключи держите за прокси-сервером. Перед отправкой в магазин убедитесь, что можете обосновать каждое разрешение. Больше о проверке того, что создают агенты, читайте в статье ревью кода с ИИ, а о выборе инструментов — в лучших ИИ-инструментах для кода.

Вопросы

Можно ли создать расширение для Chrome с ИИ, не умея программировать?

Простое расширение можно: большинство расширений состоит из нескольких небольших файлов, которые кодинг-агент способен написать. Но знание основ, таких как манифест, разрешения и обмен сообщениями между частями, помогает точно описывать агенту ошибки.

Чем content-скрипт отличается от service worker?

Content-скрипт работает внутри посещаемой страницы и может читать и менять её DOM. Service worker работает в фоне, независимо от страниц; он реагирует на события, делает сетевые запросы, а Chrome останавливает его в простое.

Как спрятать API-ключ в расширении Chrome?

Никак: всё, что вы поставляете внутри расширения, пользователь может прочитать. Держите ключ на своём сервере, пусть расширение обращается к вашему серверу, а сервер вызывает настоящий API.

Сколько длится проверка в Chrome Web Store?

Точного срока нет: от нескольких часов до нескольких дней, иногда дольше. Расширения с широкими разрешениями или трудночитаемым минифицированным кодом обычно проверяют подробнее.

Может ли ИИ перевести расширение с Manifest V2 на Manifest V3?

Да, агенты хорошо справляются с такой миграцией: фоновая страница становится service worker, удалённый код попадает в пакет, постоянные переменные переезжают в chrome.storage. После этого проверьте каждую функцию вручную, потому что остановка service worker меняет поведение.

Соберите своих агентов за одним столом.

Скачайте AgentVera бесплатно; ваши установленные CLI уже готовы к работе.

Другие статьи