Создаем расширение Chrome на Mint

В последней статье я рассказывал о том, почему мне понравилось использовать Mint для создании небольшого веб-приложения, а именно расширения Chrome.

Разработка расширения с помощью Mint, в принципе, проста, но все же с парой сложностей на ее пути я столкнулся. Сегодня я поделюсь с вами о том, как:

  1. быстро настроить разработку расширения Chrome на Mint;
  2. добавить в него функциональность с помощью Chrome Storage API.

В этой статьей мы создадим демо-расширение для Chrome. Весь код доступен на GitHub.

Что мы получим?

В конечном итоге у нас получится простой счетчик, в котором значение счета будет сохраняться в хранилище браузера Chrome. При этом оно будет сохраняться между вкладками, когда браузер закрыт, а также синхронизироваться с другими браузерами Chrome, в которых пользователь авторизован.

Если вам интересно более сложное приложение, созданное на Mint, то загляните в этот репозиторий. Оно использует API Omnibox и Storage, демонстрируя гораздо более богатую функциональность Mint для создания веб-приложений.

Как создать расширение Chrome на Mint

Этот процесс можно разбить на три части:

  1. Настройка обычного веб-приложения Mint как всплывающего расширения  —  небольшого UI, возникающего при клике по иконке в панели инструментов. 
  2. Создание приложения в формате расширения Chrome путем доработки предустановленной продакшен-сборки Mint.
  3. Добавление функциональности с помощью Chrome API за счет внутренней совместимости Mint c JavaScript.

1. Создаем новое приложение Mint

Набросать новое приложение легко. Сначала установите Mint, после чего следуйте этим инструкциям для инициализации и запуска приложения командами mint init и mint start

В итоге терминал должен показать следующее:

По адресу http://localhost:3000 вы должны увидеть приветственное сообщение “Hello Mint!” от приложения.

Теперь преобразуем его в простое приложение-счетчик. В файле Main.mint определите состояние counter для хранения значения счета и его отображения вместе с кнопками увеличения и уменьшения.

Если вы не знакомы с Mint, компонентами или стилизацией, обратитесь к документации.

После применения дополнительного стиля к кнопкам (в код выше стиль не включен) приложение должно выглядеть так:

2. Сборка приложения в формате Chrome

Приложение собирается командой mint build, которая объединит все готовые к продакшену ресурсы в каталоге dist. Этими ресурсами будут файлы HTML и JavaScript, файл манифеста JSON и множество иконок.

Далее нужно из этой сборки кое-что удалить:

  1. Service Worker, потому что в файле index.html этот работник регистрируется во встроенном скрипте. Согласно политике безопасности контента, в расширениях Chrome встроенные скрипты использовать нельзя.
  2. Иконки, просто потому что Mint генерирует множество иконок разного размера, а нам нужна всего одна.

Для удобства есть специальные флаги, которые можно передать в команду build для реализации обеих перечисленных задач:

mint build --skip-service-worker --skip-icons

Мы удалили все иконки, но нам все же нужна одна, которая будет использоваться в качестве пиктограммы приложения для его узнаваемости в панели инструментов. Выберите небольшое изображение (в идеале квадратное или круглое), сохраните его в корне проекта, после чего скопируйте в каталог dist:

cp icon.png ./dist

В завершении нужно заменить сгенерированный файл manifest.json на тот, который определяет наше расширение Chrome.

Всем расширениям Chrome требуется файл manifest.json, описывающий само расширение (имя, версию, требуемые разрешения браузера и многое другое). Определите в корне проекта manifest.json со следующим содержимым:

Обратите внимание, что он определяет index.html как default_popup, а также использует файл icon.png в качестве пиктограммы приложения. Позже мы вернемся к добавлению дополнительных атрибутов, а именно необходимых разрешений браузера.

Скопируйте новый файл манифеста в каталог dist на замену сгенерированного Mint:

cp manifest.json ./dist

Все только что проделанное для подготовки сборки расширения Chrome можно выполнить одним скриптом оболочки, который мы назовем build.sh:

build.sh

Разрешив выполнение этого файла сценария (chmod 755 build.sh), можно собрать приложение, выполнив ./build.sh. Вывод сборки попадет в каталог dist и будет доступен для тестирования в Chrome.

В Chrome перейдите в chrome://extensions и убедитесь, что находитесь в “Developer mode”. Кликните кнопку “Load Unpacked” и выберите каталог dist, содержащий последнюю сборку приложения.

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

В последней части статьи мы реализуем сохранение этого значения при помощи Chrome Storage API.

3. Доработка приложения с помощью JavaScript и Chrome Storage API

На этом этапе нужно ненадолго отвлечься от Mint и написать немного простого JavaScript. Этот код будет использовать Chrome Storage API для выполнения двух задач.

  1. Сохранения значения “count” в хранилище Chrome.
  2. Извлечения этого значения из хранилища.

Создайте файл js/index.js и напишите функцию для каждой их этих двух задач. Ввиду асинхронности Storage API обе этих функции должны возвращать промис:

js/index.js

Прежде чем расширение сможет использовать эти функции JS, нужно обновить конфигурацию в mint.json и manifest.json.

Добавьте в mint.json раздел для “external JavaScript”, чтобы приложение Mint включило новый JS-файл в сборку:

"external": {
  "javascripts": [
    "js/index.js"
  ]
}

А чтобы Chrome дал разрешение на использование расширением его хранилища, добавьте в раздел “permissions” следующее:

"permissions": [
  "storage"
]

Наконец, расширение Mint может использовать хранилище браузера. Функции chromeGetCount и chromeSetCount, которые мы определили (и включили в сборку как “external JavaScript”), доступны глобально в итоговой JS-сборке приложения. Это означает, что в коде Mint мы можем вызывать их отовсюду, если сообщим компилятору Mint, что это JavaScript, заключив его в обратные кавычки. Подобный вызов JS-функций внутри кода Mint является примером внутренней совместимости этих языков.

Теперь приложение-счетчик работает с двумя экземплярами “count”: значением, хранящемся в локальном состоянии в компоненте Main.mint, и значением, которое будет храниться в хранилище браузера Chrome. Приложению необходимо синхронизировать оба этих значения. Это значит, что при вызове функций increment или decrement счет должен обновляться в обоих местах:

Подробнее о выражении Mint parallel можно прочитать в документации.

Теперь, когда Chrome Storage является надежным источником истины, можно считывать оттуда значение счета и инициализировать с его помощью значение состояния counter компонента. Это должно происходить при каждом открытии всплывающего окна (то есть при первичном монтировании компонента):

Еще одно, возможно, незнакомое вам выражение Mint  —  это sequence, о котором также рекомендую почитать в документации. Его применение гарантирует разрешение промиса chromeGetCount() в значение до того, как следующая строка кода установит состояние counter равным этому значению. На языке JavaScript эта функция становится подобной следующему:

Вот теперь приложение работает, как нужно.

  • Счет можно изменять при открытии окна расширения, обновляя значение локального состояния и значение в хранилище Chrome.
  • Всплывающее окно при открытии всегда будет показывать текущее значение, считывая его из хранилища Chrome.

Заключение

Хоть Mint может и не показаться очевидным выбором для создания расширений Chrome, он определенно для этого неплох.

Создавать веб-приложения с помощью этого языка (например, всплывающие расширения Chrome) можно легко и быстро, а возможность Mint тесно взаимодействовать с кодом JS означает, что он отлично подготовлен к разработке этих расширений.

Читайте также:

Читайте нас в TelegramVK и Яндекс.Дзен


Перевод статьи Chris Vibert: Build a Chrome Extension With Mint

Предыдущая статьяИспользование конкурентности при создании API в Go
Следующая статьяЧто в голосе моем? - Код!