Hello, Word! Разрабатываем браузерное расширение в 2021-м
Меня зовут Саша Коновалов, я разработчик в компании Oxonit и наставник на программе «Мидл фронтенд-разработчик» в Яндекс.Практикуме.
На примере разработки расширения «Hello, Word» я расскажу, как разрабатывать кроссбраузерное расширение со знаниями современного фронтенда:
- для чего нужно кроссбраузерное расширение;
- как его разработать под разные браузеры;
- модульность кода, как переиспользовать компоненты и как современный фронтенд помогает в разработке расширений;
- какие инструменты можно использовать для сборки и публикации расширений (webpack, web-ext).
Если вам интересно посмотреть исходники, я разместил их на GitHub.
Структура расширения, о котором я расскажу в статье, близка к проекту SponsorBlock. Этот проект вдохновлял меня во время работы над собственным.
Итак, создадим расширение — Hello, Word!
Hello, Word — это расширение для перевода и запоминания слов. Оно стало прототипом моего пет-проекта Wordzzz, поэтому в посте я буду приводить примеры из него.
Рисунок 1. Описание функциональности
Что делает расширение?
- выполняется на любом сайте (добавить функциональность на сайты — content-скрипт):
— по выделению слова появляется иконка, при клике делается запрос на сервис перевода и открывается окошко перевода слова (1a);
— также слово можно перевести, используя контекстное меню по правой кнопке мыши на выделенном слове (1b); - из окошка перевода можно добавить слово во внутренний словарь для истории и дальнейшего повторения (для передачи между различными частями расширения используется postMessage, для хранения слов — storage);
- считает слова (нотификации) в background-скрипте (2);
- помогает увидеть список внутреннего словаря в меню расширения и отредактировать его (всё та же связка postMessage + storage) (3);
- позволяет тренироваться в изучении новых слов в отдельном окне (отдельная страница внутри расширения — learn-скрипт) (4).
Архитектура расширений
Схема архитектуры расширений. Источник: developer.mozilla.org
MDN Web Docs определяет расширение как набор файлов, который заботливо упакован для дальнейшего распространения и установки в браузер. Ниже указаны файлы, которые могут присутствовать в расширении.
manifest.json — обязательный файл для любого расширения. В нём содержатся имя расширения, требуемые разрешения и версия, а также указатели на другие файлы расширения.
Помимо этого в манифесте могут быть и указатели на другие файлы, например:
- background pages — отвечает за долгоиграющую логику;
- иконки и любые кнопки, которые расширение может определить;
- sidebars, popups, and options pages — HTML-документы, предоставляющие содержимое для разных компонентов интерфейса пользователя;
- content scripts — исполняемые на страницах JavaScript-сценарии расширения;
- web-accessible resources — отвечает за то, чтобы контент вашего расширения стал видимым для скриптов и веб-страниц.
Наложим эту структуру на наш проект:
Рисунок 2. Архитектура расширения Hello, Word!
Архитектура проекта
Можно разрабатывать простые расширения, как в инструкции от Chrome. Мне же интересно расширить эту инструкцию для более сложных проектов, где надо добавить общие компоненты, системы сборки, кроссбраузерность, react, typescript — всё, без чего сложно представить современный фронтенд-проект.
Рисунок 3. Архитектура проекта Hello, Word!
Из рисунка выше видно, что проект состоит из нескольких частей:
- Common — здесь хранятся общие компоненты, стили и т. д.;
- Extension — само расширение Hello, Word!
- Web — небольшой лендинг для проекта;
- свой вариант может быть разным (даже другое расширение, почему нет?). В Wordzzz мы добавили ещё react-native-проект, дополнительно — сервер и разные интересные идеи и эксперименты.
Структура проекта
Управлять связями между пакетами помогает инструмент lerna (подробнее про настройку и использование можно прочитать на официальном сайте). Как и писал выше, в Common — общие стили и компоненты, общая статика (шрифт и иконки) в public-папке в корне. Web и Extension используют общие компоненты.
Рисунок 4: Структура проекта
В моем случае все пакеты собираются с помощью webpack. Для Extension собираются пять бандлов в дистрибутиве (в соответствии с Рис. 3), manifest.json, в котором указываются эти бандлы, и копируется статика.
Общие компоненты используются в соответствии с инструкцией lerna.
Для запуска расширения используется инструмент web-ext — он устанавливает расширение и позволяет подхватывать изменения кода в это установленное расширение.
Но у инструмента есть и ограничения: расширение может не загрузиться правильно в первый раз. В этом случае поможет сочетание с простым способом — обновлять вручную через панель расширений (в основном для изменений контент-скриптов).
Описание инструментов можно найти здесь.
Как достигается кроссбраузерность
1) Отдельные manifest под разные цели и браузеры
Собирается вебпаком c помощью небольшого написанного модуля под разные окружения и браузеры. В FF, например, нужно расширять наш исходный manifest.json добавлением browser_specific_settings.gecko.id.
2) Safari: конвертация кода в xcode-проект
Пользуюсь конвертером от Apple:
xcrun safari-web-extension-converter ./packages/extension/dist --project-location ./packages/extension/safari --app-name HelloWord --swift --bundle-identifier app.wordzzz.HelloWord
Я указал --bundle-identifier своего сайта app.wordzzz.HelloWord, вы укажете свой.
Если всё прошло успешно, то увидим такое сообщение:
После конвертации откроется проект и рекомендации не использовать некоторые функции (об этом ниже).
Жмём кнопку Run в XCode и смотрим, как всё работает.
Примечание: Может потребоваться включить «Разрешить неподписанные расширения» в меню «Разработка».
3) Проверка в CSS и немного про пути
До файлов в chromium-браузерах и FF разный относительный путь, поэтому я использовал css-селекторы:
/* firefox */
@-moz-document url-prefix() {
.hw-icon__logo-content {
background: url("../images/logo.svg") no-repeat;
}
}
/* not firefox */
@supports not (-moz-appearance:none) {
.hw-icon__logo-content {
background: url("chrome-extension://*MSG@@extension_id*_/images/logo.svg") no-repeat;
}
}
4) Проверка в JS
Тут ничего нового — проверка navigator.userAgent.
Например, при публикации в AppStore меня просили убрать кнопку доната.
5) Рекомендации по (не-)использованию определённых функций
Полезные ссылки
Вместо заключения
Как видите, разработать расширение можно и с современным стеком технологий. Я описал свой стек, но можно использовать и другой, важнее было показать подход в целом.
В проекте Hello, Word ещё много чего можно сделать, например, покрыть типами и тестами, использовать препроцессоры и многое другое. Предлагайте в комментариях полезные идеи для улучшения проекта и свои решения и полезные инструменты для разработки расширений. Всем мир.