はじめに

久しぶりに、Add-on SDKを触ってFirefoxのアドオンを作成したのでその時の環境作りについてメモです。

内容は以下のような感じ

  • Addon SDKの概要
  • Addon SDK APIのモジュールについて
  • WebStorm
  • Addon SDK APIの補完について
  • XPCOM APIのインターフェイスについて
  • アドオンのデバッグ(デバッガ)

Addon SDK

Firefoxのアドオン開発をするには、Add-on SDKを使うのが比較的入りやすいです。

Firefox 21からAddon SDKのAPIがFirefoxに取り込まれているので、Addon SDKでビルドしたアドオン以外でもAddon SDKのAPIが利用できるようになっています。

High-Level APIsと書かれてるモジュール(モジュール自体もJavaScriptで書かれてるので中見ると便利です)で、基本的な事はできるようになってます。

タブの操作、クリップボード操作、コンテキストメニュー、hotkeysでのショートカット設定、panelというポップアップのUI作成、
Greasemonkey的なURLのマッチングをしてスクリプトを動かすpage-mod、特定のURLを読み込ませてその中で動くスクリプトを送り込んで値などを取ってくるpage-worker
通知を行うnotifications等があります。

データの保存は、jsonでシンプルにオブジェクトを保存するsimple-storageやpackage.jsonに記録したい項目と入力の種類を書いておけば設定画面も一緒に作ってくれるsimple-prefs、使いづらいことに定評のあるIndexedDB APIをラップしたindexed-db
等があります。

また、Unit Testingというモジュールが最初からあり、cfx initでデフォルトテンプレートした段階で cfx testでテストを書ける環境が揃ってます。
test/httpd を使うとローカルサーバを立てられたりするので便利です。
(もう少しテストの書式が一般的だといい気がするけど。。)

また、AddonSDKでの実行はlocal.jsoncfx testの引数で指定したプロファイルをコピーして実行されるので、テストでプロファイルを壊しても、毎回キレイな状態から始まる(*要出典)のでテストしやすい環境があると思います。
Travis CIとかと似たような感じ?

Firefoxの機能自体に関係ないものだと、promiseuuid、set的な使い方をするcollection等もあったりします。

足りない機能は、通常のFirefoxアドオンと同じようにXPCOMを叩けば使えるモジュールを使える)ので、Addon SDKだからできないという事は大分少ないと思います。

XPCOMを叩くときはxpcomモジュールや、通常のアドオンと同じようにComponents.classes などを使う、Chrome Authorityが使えます。

以下みたいにAddonSDKのモジュールを公開してる人(中の人ですが)もいます。
モジュールはpackage.jsondependencies に書くことでアドオンから利用できるようになっています。

(この辺のモジュールをnpmとかcocoapodsみたいに共有する仕組みが欲しい…)

補足:

開発環境

公式ドキュメントはまあまあ充実していますが、他のブログ等のリソースが少ない問題があります。(これはJetpackがたどってきた歴史やMozillaにも問題がある気がしますが)

ドキュメントは前述したように org ドメインの方を見ましょう

以下は、WebStormを少し前提に書きますが、扱う内容自体は一般的な内容なので他のエディタ次第でも似たような事ができるはずです。

Webstorm

Addon SDKのモジュール郡では、分割代入やlet,constなどECMAScript 6の内容や、Mozilla JavaScript固有の書き方等が頻繁に使われています。

WebStormでは、利用するJavaScriptのバージョンを Setting -> JavaScript から選択できるので、ECMAScript 6 (Harmony) を選択しておくと大体問題ないです。
(一部、for eachとかアレですが、基本的にビルドインモジュールは編集しないので問題ないです)

毎回CLIから cfx run と叩いて起動するのは面倒なので、以下の様なシェルスクリプトを作って、それをExternal Toolsに設定して呼び出して起動させています。

Setting -> External Tools に以下のように登録

Program : /path/to/cfx-wrapper.sh
Parameters : -a "path/to/addon-sdk/" -w "$ProjectFileDir$"

WebStormのコンソールに結果が表示される(Console APIの内容も)ので、CLIを叩かなくても、runを繰り返せます。

Addon SDK APIの補完

AddonSDKのソースコードを見るとわかります、addon-sdk / lib / sdk / にSDKで使えるモジュールが定義されています。

見るとわかりますが、殆どJavaScriptで書かれているため、JavaScriptを静的解析できるエディタなら、モジュールの補完に利用できます。

WebStormの場合、 Setting -> JavaScript -> Libraries から addon-sdk/lib/sdk/ のディレクトリを登録する事で先ほどのJavaScriptを解析した結果を補完に利用できます。

Edit Library 2013 07 18 23 34 22

Setting -> Direcotories に 先ほどの addon-sdk/lib/sdk/ のディレクトリを追加することでも同じようにAddonSDK APIの補完が効きます(Librariesに追加するほうが汎用性がありますが)

Preferences 2013 07 18 23 32 35

JavaScriptで書かれているので、モジュールが実際にどういう処理をしているのかも簡単に確認できるのは利点です。

JSDoc

AddonSDK APIは比較的問題なく(Chrome Script < -> Content Scriptは理解するまで分かりにくいですが…)、馴染めると思います。

しかし、ビルドインモジュールで足りない場合はXPCOMを叩く必要があります。
例えば、ファイルのダウンロードをするモジュールは今のところないので、自分で nsIWebBrowserPersist::saveURI などを使ってやる必要があります。

これらのAPIを叩く場合は、XPCOM Interfaceに載っているようなインタフェースを知る必要が出てきます。

当然、受け取る引数もAddonSDK APIとは違い、nsIURLnsIFileなど、XPCOM Interfaceのものを扱う必要がでてきて一気に難易度が上がります。

表題に戻って、これらのXPCOM InterfaceをJSDoc(ver3)に変換して少しでもエディタが解釈できる形に落としこみたいと思います。

XPCOMはXPIDLという言語で書かれたインターフェイスファイルが公開されていて、そこにAPIのインターフェイスがのっているのでそれを利用します。

公式に、pyxpidlというものが公開されていて、これはXPIDLの内容をC++とJavaのインターフェイスファイルを生成してくれます。(何でJSDocないの…)

これを改造してXPIDL -> JSDocに変換できるようにしたazu/XPIDL-JSDOCというものを適当に作りました。
(汚いというレベルじゃないので、誰かちゃんと作って欲しい…)

  • Gecko/XULRunner SDK をダウンロードしてxulrunner-sdk/sdk/binに上書きしたら適当に動きます。

こういう感じのJSDocを書き出します。
(propertyの型もちゃんと設定したかったけど、Pythonわからなくて諦めた)

/** 
 * nsIURL IDL
 * @typedef {Object} nsIURL
 * @property filePath attribute AUTF8String filePath;
 * @property query attribute AUTF8String query;
 * @property directory attribute AUTF8String directory;
 * @property fileName attribute AUTF8String fileName;
 * @property fileBaseName attribute AUTF8String fileBaseName;
 * @property fileExtension attribute AUTF8String fileExtension;
 * @property GetCommonBaseSpec AUTF8String getCommonBaseSpec (in nsIURI aURIToCompare);
 * @property GetRelativeSpec AUTF8String getRelativeSpec (in nsIURI aURIToCompare);
*/
var nsIURL = {};

WebStorm7EAP以降なら、@typedefに対応してるみたいですがこの書き方が正解なのかよく分からない…

例えば、先ほどのファイル保存する機能を持ったモジュールを作ろうとした時に、ファイル保存するXPCOMのAPIは nsIURL を引数に取るので以下のように、引数に nsIURL の型を取るといった定義を書けるようになります。
(正直APIの補完にはあんまり使えないと思います。)

  • io.js 実際につくったやつ
/**
 * ``saveURL`` Util
 * @param {Window} window
 * @param {nsIURL} sourceURI
 * @param {nsIURL} fileURI
 * @param {string} filename
 * @return {promise} promise
 */
var saveFile = function (window, sourceURI, fileURI, filename){
}

ちなみに、io.jsの方を見るとわかりますが返り値はAddonSDKのpromiseを返してます。

少なくてもエディタが何らかの補助をしてくれるなら、事故率は減るのでやっぱりキチンとしたXPCOMのJSDocが欲しいです。。

デバッグ

Addon SDKで作成したアドオンのデバッグは、Firefox buildinのデバッガを使って行う事ができます。
また、 console.log()等のConsole APIを使ったprintデバッグもできます。

2013 07 21 at 14 35

FirefoxにもChromeのようにネイティブのデバッグツールが色々増えていて、名前がややこしいですが以下の様な使い分けです。

  1. ウェブページのデバッグ(Content) -> Browser Console
  2. アドオンのデバッグ(Chrome) -> Browser Debugger

アドオンのデバッグにはChrome権限で動いてるスクリプトが見られる Browser Debugger の方を使います。

デバッガ の使い方は以下を見るといいかもしれません。

おわり

久々に、Addon SDKを触ってアドオンを作りましたが、デバッガやテスト環境、ある程度使い方がわかりやすいモジュールが揃っているので、アドオンを作る敷居は以前に比べれば低くなってきたかなと思います。
(デバッガー周りはまだ挙動不審なことが事がありますが)

今回、Addon SDKを触りだした理由はGreasemonkey以上(具体的にはDownload APIが欲しかった)のことをやろうとして、
最初はKeySnail上でささっと作りましたが、簡単なツールバーボタンのようなUIや Content(ウェブページ) < -> Chrome(アドオン) を行き来するようなものを必要になって、
userChrome.jsのようなスクリプトだと逆に面倒になりそうだったので、Add-on SDKでアドオンとして作りました。

Greasemonkeyライクな事はpage-modpage-workerを使えばできますし、
panelwidgetを使えば簡単なUIは作れるので、Greasemonkey以上の事を簡単にやりたいときに触ってみるといいんじゃないかなーと思います。