Popup ALT AttributeアドオンにおけるXUL/XPCOMからWebExtensionsへの移行
今日の投稿はPopup ALT Attributeや40 other add-onsを 開発しているpiro氏の記事からの投稿です。彼はXUL/XPCOMアドオンからWebExtensionに移行するための考えを共有し、彼がどのよう にPopup ALT Attributeを移行したかを私たちに見せてくれました。彼のブログで全文を読むことができます。
***
こんにちは、アドオン開発者のみなさん。私の名前は結城洋志、ニックネームはPiro、そしてFirefoxアドオンの開発者です。私はとても長い期間、個人的に、またビジネスで、XUL/XPCOMベースのFirefoxアドオンやThunderbirdアドオンを開発してきました。
私 は最近アドオンたちをWebExtensionに移行するために必要となるAPIのリサーチを始めました。Mozillaが”XUL/XPCOMベースの アドオンを2017年の終わりまでに廃止する”と告知したからです。私は、いくつかのアドオンが現在使用可能なAPIだけでけしか移行できることに気づきま した。Popup ALT Attribute もそれらのアドオンの中の一つです。
これは私がどのようにWebExtensionに移行させたのかを綴った物語です。
このアドオンについて
Popup ALT Attribute は2002年からスタートしているとても古くからあるアドオンで、これはwebページのimg
HTML要素の alt
属性に書かれている内容を表示するものです。通常、Firefoxはtooltipに title
属性のみ表示します。
最初に、このアドオンはFirefox自身の FillInHTMLTooltip()内部関数を置き換える機能が実装されています。
2016年1月、私はこのアドオンを e10s に対応させました。このことはあなたのアドオンの状態によって価値が変わるでしょう。もしあなたが直接WebExtensionに移行するなら、WebExtensionはデフォルトでe10sに対応しているからです。
WebExtensionスタイルに再フォーマッティング
私は移行する前に、どのように1からWebExtensionベースのシンプルなアドオンを作るかのチュートリアルを読み、WebExtensionはブートストラップ型拡張に似ていることに気が付きました。
- 両者は動的にインストール、再インストールされる
- 両社は主にJavaScriptコードがベースでいくつかの静的なマニフェストファイルを持っている。
私はすでにこのアドオンをbootstrapped型アドオンに移行していたため、容易にWebExtensionに再構成することができました。
これは私が書いた初期のバージョンの manifest.json
です。これはlocalizationやオプション用のUIがありません
<code>{ "manifest_version": 2, "name": "Popup ALT Attribute", "version": "4.0a1", "description": "Popups alternate texts of images or others like NetscapeCommunicator(Navigator) 4.x, and show long descriptions in the multi-row tooltip.", "icons": { "32": "icons/icon.png" }, "applications": { "gecko": { "id": "{61FD08D8-A2CB-46c0-B36D-3F531AC53C12}", "strict_min_version": "48.0a1" } }, "content_scripts": [ { "all_frames": true, "matches": ["<all_urls>"], "js": ["content_scripts/content.js"], "run_at": "document_start" } ] }</code>
私 はすでにmain scriptをフレームスクリプトとloaderに分けていました。一方、 manifest.json
はどのようにロードされたかを述べるための いくつかのマニフェストキーを持ちました。これはパッケージに自作したカスタムloaderを何も追加する必要のないことを示しています。実際、上記のサ ンプルに含まれている content_scripts
ルールによってどんなwebページにもスクリプトをロードすることができます。 content_scripts
の詳細はドキュメントをご覧ください。
そして最後には、3つのファイルにすることができました。
Before:
<code>+ install.rdf + icon.png + [components] + [modules] + [content] + content-utils.js</code>
And after:
<code>+ manifest.json (migrated from install.rdf) + [icons] | + icon.png (moved) + [content_scripts] + content.js (moved and migrated from content-utils.js)</code>
そして、私はまだ、XPCOMから自分のフレームスクリプトを分離する必要があります。
- scriptは
nsIPrefBranch
やXPConnectを通していくつかのXPCOMとつながっています。そのためそれらを一時的にコメントアウトします。 - ユーザープレファレンスは使用不可になり、値を固定し、デフォルト設定のみ使用可能になります。
Ci.nsIDOMNode.ELEMENT_NODE
のように、いくつかの定数のプロパティにアクセスされるXPCOMコンポーネントをNode.ELEMENT_NODE
のような形に置き換えました。webページから mousemove
eventsを取得するリスナーはフレームスクリプトのグローバル名前空間にアタッチされますが、しかしこれはそれぞれのページのdocument自身に
再アタッチされます。なぜなら現在 scriptはwebページで直接実行されるからです。
ローカライズ
xpcomアドオンのinstall.rdfでは、説明をローカライズしていました。webextensionでは異なった方法でローカライズする必要があります。詳細はhow to localize messagesをご覧ください。以下で簡単な説明を行います:
ローカライズした説明を記述するためにファイルを追加します
<code>+ manifest.json + [icons] + [content_scripts] + [_locales] + [en_US] | + messages.json (added) + [ja] + messages.json (added)</code>
en_US
はinstall.rdf
のバージョンのen-US
と異なることに注意してください。
English locale, _locales/en_US/messages.json
です:
<code>{ "name": { "message": "Popup ALT Attribute" }, "description": { "message": "Popups alternate texts of images or others like NetscapeCommunicator(Navigator) 4.x, and show long descriptions in the multi-row tooltip." } }</code>
日本用のlocale, _locales/ja/messages.json
もまた含まれています。そして、manifest.json
をローカライズされた言葉を埋め込むために修正する必要があります。
<code>{ "manifest_version": 2, "name": "__MSG_name__", "version": "4.0a1", "description": "__MSG_description__", "default_locale": "en_US", ...</code>
__MSG_****__
文字列変数は自動的にローカライズされたメッセージに置き換えられます。default_locale
キーを通して、手動でデフォルトロケールを設定することが必要です。
残念ながら、firefox45ではローカライゼーション機能はサポートされていません。そのためlocalizationを行うには Nightly 48.0a1以上のバージョンが必要になります。
ユーザープレファレンス
現在、WebExtensionsはnsIPrefBranch
と互換性 を持っている機能を提供していません。しかし、代わりに、シンプルなストレージAPIを持っています。これはuser preferencesをset/getするための nsIPrefBranch
の代わりに使えます。このアドオンはUIの設定をもっていません。しかし拡 張的な機能をコントロールするためにいくつかのsecret preferencesをもっています。そのため私の他のアドオンの移行のために試験的に挑戦しました。
そして私は大きな壁にぶつかります。ストレージAPIはコンテンツスクリプトでは使用可能ではないのです。私はストレージにアクセスするだけのため にバックグラウンドスクリプトを作成することが必要で、さらに内部サンドボックスメッセージシステムを通してコンテンツスクリプトとコミュニケーションを とる必要があります。(更新情報: bug 1197346はNightly 49.0a1では修正されています。そのためコンテンツスクリプトからストレージシステムにアクセスするようなハックはもう必要ありません。現在、私はネイティブなストレージAPIの代わりに設定値に簡単にアクセスできるようなライブラリ(configs.js)を提供しています。)
最後に私はそれを行うために小さなライブラリを作成しました。私はここでは説明しませんが、もしあなたが詳細を知りたいなら、ソースコードをご覧ください。177行のライブラリがあります。
私は二つのバックグラウンドスクリプトやコンテンツスクリプトを使用するために、自分のmanifest.jsonを更新する必要がありました。
<code> "background": { "scripts": [ "common/Configs.js", /* ライブラリ自身 */ "common/common.js" /* ライブラリを使用するコード */ ] }, "content_scripts": [ { "all_frames": true, "matches": ["<all_urls>"], "js": [ "common/Configs.js", /* ライブラリ自身 */ "common/common.js", /* ライブラリを使用するコード */ "content_scripts/content.js" ], "run_at": "document_start" } ]</code>
同じセクションに記載されているスクリプトはセクションの名前空間を共有しています。他からscriptをロードするためにrequire()のようなも のは必要ありません。代わりに、私は各リストのscriptの並び順に気を付け、ライブラリを必要とするスクリプトが、必要とされるライブラリ自身の後に なるように書く必要があります。
そして最後の障害に当たります。about:cofigやMCDに当たる動作を実現するにはどうすればいいのか・・・一般的な方法はアドオン全体にわたる秘密のプレファレンスを制御することです。
私は仕事の顧客に対し、大抵アドオンを提供して、彼らの設定をロックするためにMCDを使用しま した。(Firefoxをビジネスで使用するためにいくつかの共通の要件があるため、アドオンとMCDの組み合わせは、それぞれの顧客用に異なった設定の Firefoxプライベートビルドを作成するよりもかけるコストが少なくて済みます。)
私はまだこの当たりを探る必要があると考えました。
Options UI
WebExtensions はアドオンに対してオプションページを作成する機能を提供しています。これも同じく、Firefox45ではサポートされていません。そのため現在あなた はNightly 48.0a1を使用する必要があります。前に私が言った通り、このアドオンはコンフィグ用にUIを持ちません。しかし私は勉強用に試してみました。
XUL/XPCOMアドオンでは、<checkbox>
, <textbox>
, <menulist>
や他にもリッチなUI要素が使用可能です。しかしこれらは来年末までに使用不可能になります。なので私は純粋なHTMLとJavascriptベースのカス タム設定用UIを実装する必要がありました。(もしあなたがもっとリッチなUIの要素を必要とするならWebApplication用のライブラリなどが 助けてくれるでしょう。)
このステップで私は2つのライブラリを作成しました。
- A helper to bind configurations to UI elements.
- A helper to apply localized messages to a static HTML.
終わりに
私は自分のPopup ALT AttributeアドオンをXUL/XPCOMからWebExtensionsに移行することに成功しました。現在ここのブランチにありますが、Firefox48が使用可能になってからリリースしようと思っています。
これが私が移行することのできた理由です。
- これがブートストラップ型拡張でした、そのため既にアドオンに破壊的な変更を行う必要がありませんでした。
- このアドオンの中心の実装はシンプルなユーザースクリプトに似ていました。アドオンの中心的な動作は、コンテンツスクリプト中で動作します。そしてこれを行うために、特権を必要としていません。
しかし、これは珍しいケースです。私の他の40以上のアドオンはいくつかの特権を必要とし、コンテンツエリアの外側で動作します。私のアドオンのほとんどは、このような非典型的なアドオンです。
私は複数の新しいAPIをリクエスト、分類、計画などを立てたりすることが必要があります。これは私だけではなく、他のアドオン開発者も同じでしょう。
読んで頂きありがとうございます。