ブラウザ拡張機能をつくろう
ブラウザ拡張機能について
拡張機能とは
ブラウザ拡張機能(以降、拡張機能)は、ブラウザの機能を拡張・修正するものです。通常のウェブページでの機能と異なり、 拡張機能用の強力なAPIを使うことができます。
また、Extension APIは拡張機能をサポートする主要ブラウザで互換性があるため、一つのコードで複数のブラウザに対応した拡張機能を実装できます。
ちなみに、Chrome Web Store ではそのまま拡張機能と呼ばれますが、Firefox Browser Add-ons ではアドオンという呼び方で統一されています。
何ができるのか
拡張機能では、ポップアップで独立したアプリケーションを構築したり、表示しているウェブサイトにコンテンツを挿入して機能を拡張したり、バックグラウンドで継続して処理を実行し続けたりできます。
拡張機能では主に以下の4つの領域でコードを実行できます。
Background Scripts:拡張機能がインストールされてから無効化・アンインストールされるまでロードされた状態が維持されます。モニタリングや処理の定期実行、などができます。 Content Scripts:ウェブページに独自のコードを挿入します。クロスドメインのXHRリクエストやExtension APIのサブセットが使用できます。
Page Action:
Popup:拡張機能のアイコンをクリックすると表示されるポップアップ
Options Page:拡張機能の設定ページ
拡張機能を作ってみよう
今回作る拡張機能
Backlog のお知らせの一覧をポップアップで表示し、バッジに未読のお知らせ件数を表示する拡張機能を例に、開発の流れを説明します。
開発環境
ここでは、Webpack + TypeScript + React + Tailwind CSS の技術スタックで拡張機能を開発します。
webpack.config.js は次のようになりました。
POINT: devtool は eval を使用しない設定にする
拡張機能では外部からの悪意のあるコードの実行を防ぐため、eval() の実行が禁止されています。
Webpack の development モードでのデフォルトのコードは eval() を使用するので、拡張機能で動作させるために eval() を使用しない設定に変更する必要があります。
ソースコードでは devtool: 'source-map' としていますが、ビルドスピードなどを見ながら調整しましょう。
manifest.json を作る
manifest.json はその拡張機能の基本的な設定やどのAPIへの権限を要求しているかなどをまとめた定義ファイルです。
最新のバージョンは 3 ですが、ここでは 2 で定義しています。
POINT: CopyWebpackPlugin を活用する
静的なファイルを outputs としてコピーする CopyWebpackPlugin ですが、コピーする際にファイルの内容を変換できる transform というオプションを指定できます。 たとえば、「manifest.json の version を package.json と揃えたい」ときに、 transform オプションと lodash.template を使って JSON ファイルに動的な値を挿入することができます。
ブラウザで動作を確認する
manifest.json を作成したら、ブラウザで動作できるようになります。
Google Chrome の場合は chrome://extensions から、 Firefox の場合は about:debugging からそれぞれパッケージされていない拡張機能をインストールできます。
コードの変更を反映するためには、webpack --watch でソースコードをビルドし、反映されたらポップアップやオプションページを開き直しましょう。
(もしかしたら、webpack --watch + web-ext run でホットリロードできたりするかも)
コンソールの出力を確認する
オプションページを作る
POINT: Extension API へは Polyfill を使ってアクセスする
Extension API へのアクセス方法はブラウザによって異なります。
たとえば、スタンダードな Extension API は browser をグローバルオブジェクトとして提供しているのに対し、Google Chromeは chrome がグローバルオブジェクトとなっており、ブラウザ間に差異があります。
この差異を吸収するために、基本的に webextension-polyfill-tsから Extension API へアクセスするようにすると便利です。
ただし、ブラウザ間でサポートされていないプロパティやメソッドが普通に存在するので、注意して実装しましょう。
Firefox しか対応していないメソッド
POINT: 設定は Storage API でブラウザに保存する
拡張機能で保持したいデータは Storage API でブラウザに保存できます。
Storage API を使用するためには、 manifest.json の permissions に storage を追加する必要があります。
ポップアップを作る
POINT: 拡張機能からアクセスするURLはパーミッションで明示する必要がある
拡張機能では、manifest.jsonのパーミッションで指定されていないURLへリクエストすることはできません。
リクエストする必要のあるURLのパターンをpermissionsに列挙します。
ワイルドカードなパターン(*://*/*)でも動作はしますが、事故防止のために使用が想定されるパターンを指定するようにしましょう。
なお、Manifest V3からhosts_permissionsという項目が追加されたようなので、V3ではそちらに列挙しましょう。
POINT: ポップアップからオプションページを開く
次のメソッドで、ポップアップからオプションページを開くことができます。
設定されていない状態でポップアップを開いたときなどに便利です。
バックグラウンドで定期的に件数を取得する
POINT: 定期実行には Alarms API
バックグラウンドスクリプトでは、setInterval などのタイマーは使用できません。
代わりに、定期実行を行う Alarms API が提供されているので、何かを定期的に実行したい場合は Alarms API を使用しましょう。
なお、Alarms API を使うためには permissions に alarms を追加する必要があります。
拡張機能としてビルドする
拡張機能としてビルドするには、 Mozilla がメンテナンスしている web-ext が便利です。
シンプルな拡張機能の場合はただ ZIP にまとめられるだけですが、コードのリンターやサインの作成など拡張機能をリリースするにあたって必要な機能が揃っています。
拡張機能をリリースする
Chrome Web Store
利用料としてはじめに$5支払います。以降は、指示にしたがって拡張機能のアップロードと各種紹介文、権限の説明を記載して審査申請します。今回は1日半くらいで審査が完了しました。
Firefox Browser Add-ons
Chrome Web Store のように利用料を払うことはないですが、リリースのためにソースコードを送付する必要があります。また、拡張機能を検証するためにアカウントが必要な場合は、開発者アカウントの情報を共有する必要があるかもしれません。
入力項目は Chrome Web Store より多いですが、審査自体は1日程度で完了し、リリースされました。
MEMO: 拡張機能はいつ更新されるのか
網羅的に確認できたわけではないですが、Google Chromeはブラウザを完全に終了して、起動した際に更新がかかるようでした。
TODO: リリースを自動化する
Chrome Web Store / Firefox browser add-ons では、拡張機能のアップロードと公開を行えるAPIが提供されています。
うまくCDフローを組めばリリース作業を自動化できそうです。