Manifest V3 и устройство расширения
«Заметки читателя» — учебное расширение, которое сохраняет выбранную страницу, выделенную цитату и собственную заметку. Данные останутся локальными, а экспорт будет создан из записей самого пользователя. Начнём с описания пакета и минимального popup. К концу урока вы сможете объяснить, почему расширение состоит из нескольких контекстов и где браузер узнаёт о его точке входа.
Серия использует конкретный профиль: Chrome Manifest V3, обычный JavaScript и локальные HTML-файлы без сборщика. Это не обещание одинаковой платформы всех WebExtensions. Firefox рассматривается в конце как отдельный перенос с другим договором background и manifest. Требуются основы объектов JavaScript, DOM, событий и JSON. Расширение при подготовке не устанавливалось, не запускалось и не публиковалось; все описания экрана являются ожидаемыми.
Manifest как договор с браузером
manifest.json описывает пакет, а не исполняет предметные операции. Поле manifest_version имеет значение 3, name содержит название, version — номер нашего расширения. Этот номер отличается от версии Chrome и от версии формата пользовательского экспорта. Уже на первом шаге полезно отделить их: изменение продукта не обязательно означает изменение JSON-данных, а новый браузер не меняет автоматически номер пакета.
Поле action.default_popup связывает кнопку расширения с popup.html. Когда пользователь вызывает action, браузер должен открыть локальную страницу пакета. default_title задаёт понятную подпись действия. Здесь нет сервера и сетевого URL интерфейса. Поэтому popup остаётся страницей расширения со своим происхождением, а не частью текущего сайта. Код чужой страницы не должен получать управление этим интерфейсом просто из-за того, что оба видны в одном окне браузера.
Минимальный manifest пока не требует разрешений. Мы не читаем вкладку, не сохраняем заметки и не внедряем код. Это полезная исходная граница: новые возможности будут вводиться тогда, когда появляется конкретная обязанность. Наличие широкого доступа не требуется для показа локального заголовка. Позднее activeTab позволит временно прочитать выбранную вкладку после действия пользователя, scripting — выполнить наш файл, storage — сохранить собственные записи.
Полные файлы шага
Показанные файлы полностью совпадают с выбранным состоянием архива. Остальные согласованные файлы находятся в examples/browser-extension-lab/lesson-01/.
manifest.json
{
"manifest_version": 3,
"name": "Заметки читателя",
"version": "0.1.0",
"minimum_chrome_version": "102",
"description": "Локальные заметки о самостоятельно выбранных страницах",
"action": {
"default_popup": "popup.html",
"default_title": "Заметки читателя"
}
}
popup.html
<!doctype html>
<html lang="ru">
<head><meta charset="utf-8"><title>Заметки читателя</title></head>
<body><h1>Заметки читателя</h1><p>Расширение открывает локальный popup.</p></body>
</html>
Ожидаемый результат
Это ожидаемый договор для самостоятельного исследования; расширение не устанавливалось и не запускалось.
Ожидается локальный popup «Заметки читателя».
Доступ к страницам и постоянное хранение ещё отсутствуют.
Контексты, которые появятся дальше
Popup имеет DOM и короткую жизнь: закрытие окна уничтожает его текущий интерфейс. Service worker будет обрабатывать события расширения и не имеет DOM. Content script выполняется в контексте выбранной вкладки и читает её документ в изолированном мире. Эти области не являются одним JavaScript-файлом с общей памятью. Чтобы передать данные, понадобится сообщение или результат scripting.executeScript. Чтобы сохранить состояние после завершения контекста, понадобится отдельное хранилище.
Именно такое разделение определяет дальнейший проект. Пользователь пишет заметку в popup, наш content script получает название и выделение, worker проверяет команду и записывает данные. Options будет долгоживущей страницей настроек и переноса JSON. В первой главе этих файлов ещё нет: описание будущих обязанностей нужно для понимания manifest, а не для утверждения, что весь функционал уже реализован. Начальный пакет честно показывает только локальный popup.
Минимальная HTML-страница содержит русское название и короткое пояснение. Метатег charset задаёт кодировку, lang помогает интерпретации языка. Заголовок h1 внутри popup допустим: это собственный HTML интерфейса, а не Markdown-заголовок статьи. Мы не загружаем библиотеку с CDN и не вставляем встроенный JavaScript. Когда появится поведение, подключим отдельный локальный файл, чтобы код был частью обозримого пакета и соответствовал выбранному профилю Manifest V3.
Нижняя граница API
minimum_chrome_version указан как 102. В поздних ступенях понадобится storage.setAccessLevel, документированный для Chrome 102+. Это нижняя граница выбранных API, а не заявление о проведённой проверке в старом браузере. Для самостоятельного исследования читатель использует поддерживаемый актуальный Chrome в собственном учебном профиле. Мы не выводим из одного поля manifest утверждение, что весь пакет испытан во всех выпусках от 102 до текущего.
Также поле не делает расширение Firefox-совместимым. Chrome manifest содержит соглашения конкретной платформы; отличия WebExtensions требуют отдельного анализа. Важен принцип проверки всего договора: фоновой модели, сообщения, доступных API и порядка установки. Простая замена слова chrome на browser позже не станет доказательством переноса. Пока один ясный профиль позволяет последовательно изучать механизм, не смешивая неподтверждённые платформенные обещания.
Ожидаемый результат первого состояния — кнопка «Заметки читателя», открывающая страницу с названием и пояснением. Сохранение ещё отсутствует. Если пользователь закроет popup, ничего предметного не потеряется, потому что постоянных данных здесь нет. Такое ограничение не является ошибкой недописанного storage: мы специально начинаем с упаковки и точки входа. Следующий урок добавит ввод текста и покажет, чем DOM-состояние отличается от сохранённой заметки.
Для самостоятельной установки читатель может выбрать полный lesson-01 через Load unpacked на chrome://extensions своего локального профиля. Автор этих действий не выполнял, доступ к аккаунтам не использовал. Если manifest не читается, сначала проверяют JSON и пути, а не код будущего worker. Если popup открывается, но не содержит ожидаемый текст, проверяют popup.html. Такой разбор связан с отдельными обязанностями файлов и не требует угадывать причину по общему слову «расширение».
Пакет остаётся обозримым
Снимок содержит только manifest, popup и описание состояния. Мы не включаем чужую историю браузера, данные профиля и скачанные записи пользователя. Курс будет сохранять полные файловые состояния каждого шага, чтобы читатель видел точное изменение между ними. Полнота здесь означает согласованный набор исходников, а не наличие любых возможных возможностей. На следующей ступени появится popup.js, затем worker.js, затем чтение вкладки; порядок соответствует независимым результатам.
Версия 0.1.0 относится к подготовленному учебному состоянию и не означает публикацию в магазине. Пакет передаётся локально, а формальный выпуск расширения остаётся отдельным действием. Такой договор помогает не перепутать созданный manifest с установленным продуктом. К концу главы у нас есть минимальная точка входа и карта контекстов, которые будут обмениваться проверенными данными. Теперь можно добавить пользовательское действие, сохранив эти границы понятными.
Версию пакета удобно понимать как имя состояния для передачи другому читателю. Она не создаёт пользовательские записи и не запускает миграцию local. Если два автора изучают разные lesson-NN, им важнее назвать конкретный каталог, чем предполагать совпадение всей программы по похожему интерфейсу. Поэтому в архиве сохраняется самостоятельное состояние каждого шага. Это позволяет сопоставить manifest с реально существующими файлами и не приписать ранней главе сохранение, которое вводится только позднее.
Документация и исходники
Механизмы главы сверены с первичными источниками: документация 1, документация 2, документация 3. Полный архив «Заметок читателя» содержит все двенадцать состояний. Установка, запуск и публикация не выполнялись.