jetpack library 事始め

40
Jetpack Library 事事事 2011/01/16 事事事事 事事事事事 () @asukaze55

Upload: tomohiro-kaizu

Post on 24-May-2015

2.621 views

Category:

Technology


2 download

DESCRIPTION

Mozilla 勉強会@東京 5th の発表資料

TRANSCRIPT

Page 1: Jetpack Library 事始め

Jetpack Library 事始め

2011/01/16あすかぜ (海津智宏)

@asukaze55

Page 2: Jetpack Library 事始め

自己紹介• http://www.asukaze.net/• RemoveTabs, Tabloc という、小さな拡張を公開してい

ます。• Add-on SDK (Jetpack SDK) の開発状況を追いかけて、メ

モをまとめています。• Mozilla とは関係ないですが、 Cassava Editor という

CSV エディタを公開しています。• 2010/12/01 に転職しました。転職先の会社

は、 Mozilla とは商売敵かもしれません :)• ヒキコモリ体質のため、 Mozilla の勉強会等に参加す

るのは初めてです。皆様よろしくお願いします。

Page 3: Jetpack Library 事始め

Add-on SDK (Jetpack SDK) とは?• 現在開発中の、新しい拡張開発キット。• XUL などの知識を必要とせず、 HTML, JavaScript,

CSS の知識だけで拡張が開発できるかも。• API は Firefox のバージョンに非依存。拡張を再

パッケージングするだけで Firefox の新しいバージョンに対応できるはず。

• 開発した拡張は再起動不要でインストール/アンインストール可能。

• サードパーティが自由に API を追加できる。

Page 4: Jetpack Library 事始め

History

Jetpack Prototype

Jetpack Reboot Jetpack SDK Add-on SDK

2009/05 2010/03 2010/12

開発終了

0.1 ~ 0.9 β1

feature-stable

Page 5: Jetpack Library 事始め

Prototype と SDK

Firefox

API(Jetpack Prototype 拡張 )

Jetpack Jetpack Jetpack

Firefox

Jetpack

Core

Jetpack

Core

Jetpack

Core

Jetpack Prototype Add-on SDK

Page 6: Jetpack Library 事始め

Add-on SDK 1.0b1 の API(addon-kit)

• ページコンテンツの変更• ウィンドウ操作・タブ操作• ウィジェット表示・パネル表示• コンテキストメニュー表示• 選択範囲の取得• HTTP リクエスト送信・ DOM 操作• クリップボードの取得・更新• アラートメッセージ表示• プライベートブラウジングの開始・終了• ストレージへの情報保存 以上!

Page 7: Jetpack Library 事始め

Add-on SDK 1.0b1 の API(addon-kit)

• 標準 API で GreaseMonkey +α のことはできる。• が、 XUL ベースの拡張に比べると、できるこ

とは限られている。– ブラウザ自体の UI を拡張できるのはウィジェット

とコンテキストメニューのみ

• 低レベル API を使って自作ライブラリを作れば、なんでもできる!

Page 8: Jetpack Library 事始め

Add-on SDK の低レベル API(api-utils)

• Components オブジェクトへのアクセス– {Cc, Ci, Cu, Cr, Cm, components} = require(“chrome”);

• tabbrowser 要素や window 要素へのアクセス– require(“tab-browser”)– require(“window-utils”)

• API 提供用のヘルパ関数– require(“unload”).ensure()– require(“api-utils”).publicConstructor()– require(“errors”). catchAndLog()

Page 9: Jetpack Library 事始め

できることの例• ブラウザ内の任意の場所に XUL 要素を追

加できる。• ブラウザ内の任意の場所にイベントリス

ナを仕掛けられる。

Page 10: Jetpack Library 事始め

考慮すべきこと1. 拡張が再起動不要となるようにする2. Firefox, SDK のバージョンに非依存な API

を提供する3. addon-kit の API と似た使い方を提供す

る1. construct/destroy モデル2. EventEmitter モデル3. エラー発生時のスタックトレース出力

4. その他

Page 11: Jetpack Library 事始め

1) 再起動不要• 拡張が無効化/アンインストールされた

ときに状態を元に戻すのはライブラリの責任。– ブラウザに対する変更を全て覚えておき、終

了時に元に戻す。• api-utils 内の unload モジュールを使うと、

終了時の処理を登録できる。– イベントの伝播は bootstrap.js → harness →

cuddlefish → unload という流れ。

Page 12: Jetpack Library 事始め

unload モジュールfunction Foo() { // 変更処理 require("unload").ensure(this);}

Foo.prototype = { unload: function(reason) { // 復帰処理 }};

function bar() { // 変更処理 require("unload").when( function(reason){ // 復帰処理 });}

ensure 関数にオブジェクトを登録する。終了時には、オブジェクトごとに1 回ずつ unload 関数が実行される。

when 関数にコールバック関数を登録する。複数回 when を呼び出すと、その回数分処理が実行される。

Page 13: Jetpack Library 事始め

Firefox 5.x

api-utils 2.x

addon-kit 2.x

MyLibrary 2.0

MyExtension 2.0

2) バージョン非依存

変わらないはず

変わるかも

変わるかも

Firefox 4.0

api-utils 1.0b1

addon-kit 1.0b1

MyLibrary 1.0

MyExtension 1.0変えちゃダメ

Page 14: Jetpack Library 事始め

2) バージョン非依存• Firefox の内部構造に依存しない、汎用的

な API を提供する• 今後の Firefox の変化を先取りし、あらか

じめ備えておく– E10S 対応!!

Page 15: Jetpack Library 事始め

E10S (Electrolysis) とは?• 「プロセス分離」のコードネーム。• 今後、ブラウザ本体と Web ページのコンテンツと

Jetpack 拡張は、それぞれ別プロセスで動作するようになる。

firefox.exe

jetpack process content process←メッセージ通信→

×直接アクセスはできない

Page 16: Jetpack Library 事始め

コンテンツプロセスの分離 を考慮した API

var pageSourceItem = contextMenu.Item({ label: "Edit Page Source", contentScript: 'on("click", function (node, data) {' + ' postMessage(document.URL);' + '});', onMessage: function (pageURL){ editSource(pageURL); }});

別プロセスで動作するスクリプ

メッセージ通信

プロセス間で関数オブジェクトは受け渡しできないので、コンテンツプロセスで動作する部分はスクリプトを文字列もしくは URL で受け渡す。JSON 形式に変換可能なオブジェクトはメッセージ通信で受け渡し可能。

Page 17: Jetpack Library 事始め

content モジュールfor (window in require("window-utils").windowIterator()) { require("content").Worker({ window: window, contentScript: 'postMessage("message!");', onMessage: function(data) { console.log(data); } });}

Worker として登録したスクリプトは対象の window 上で動作する。オプションは page-mod や context-menu と同様。

Page 18: Jetpack Library 事始め

Jetpack プロセスの分離を考慮した API

• cfx run に 「 --e10s」オプションを付加することで試行できる。

• SDK 本体の対応もこれから。今後の動向に注目。 – self-e10s-adapter などは参考になる

> cfx run --e10s -b "C:\Program Files\Minefield\firefox.exe"…Error: Module 'widget' requires chrome privileges and has no e10s adapter.OK…

Page 19: Jetpack Library 事始め

いまここ1. 拡張が再起動不要となるようにする2. Firefox, SDK のバージョンに非依存な API

を提供する3. addon-kit の API と似た使い方を提供する

1. construct/destroy モデル2. EventEmitter モデル3. エラー発生時のスタックトレース出力

4. その他

Page 20: Jetpack Library 事始め

3-1) construct/destroy モデルwidgets.add(widgets.Widget({ label: …, image: …, onClick: …}));

widgets.remove(w);

add/ remove モデルはもう古い!

widgets.Widget({ label: …, image: …, onClick: …});

w.destroy();

時代は construct/destroy モデル!

コンストラクタの中で初期化処理まで実行する。明示的に変更を元に戻す時は destroy メソッドを使う。

Page 21: Jetpack Library 事始め

コンストラクタ作成時に便利な関数

• new ClassName({…}) でも ClassName({…}) だけでもオブジェクトを作れるようにする。– require(“api-utils”).publicConstructor()

• オプションの内容をチェックする。– require(“api-utils”).validateOptions()

• Array もしくは スカラ値を受け取るプロパティを作る。– require(“collection”).addCollectionProperty()

Page 22: Jetpack Library 事始め

3-2) EventEmitter モデルtabs.onOpen = function(){…};tabs.onReady = function(){…};tabs.onActivate = function(){ …};tabs.onDeactivate = function(){ …};

onXXX プロパティはもう古い!

tabs.on(‘Open’, function(){…});tabs.on(‘Ready’, function(){…});tabs.on(‘Activate’, function(){ …});tabs.on(‘Deactivate’, function(){ …});

時代は EventEmitter モデル!

EventEmitter を使うことで、全てのイベントについて_emit() でのイベント送信、 on() でのイベント受信に統一できる。

Page 23: Jetpack Library 事始め

events モジュールconst { EventEmitter } = require("events");var object = EventEmitter.compose({ constructor: function() {…}, fire: function() { this._emit('event1'); }})();

object.on('event1', function(){ console.log("Event Fired!");});object.fire();

EventEmitter.compose()() は Trait という形のオブジェクトを返す。_emit() など 「 _」から始まるメソッドは、 this からしか呼び出せない。

Page 24: Jetpack Library 事始め

3-3) スタックトレース出力• 実行時エラーの発生時、放っておくと何も言わずに処理が終了してしまう。きちんとスタックトレースを出力するように注意する。– EventEmitter を使っていれば、自動的にやっ

てくれるので問題ない。– それ以外でコールバック関数に処理を渡すと

きは、 require(“errors”).catchAndLog() を使う。

Page 25: Jetpack Library 事始め

いまここ1. 拡張が再起動不要となるようにする2. Firefox, SDK のバージョンに非依存な API

を提供する3. addon-kit の API と似た使い方を提供する

1. construct/destroy モデル2. EventEmitter モデル3. エラー発生時のスタックトレース出力

4. その他

Page 26: Jetpack Library 事始め

配布• https://builder.addons.mozilla.org/ にライブ

ラリとして登録する。– が、、、 Add-on Builder ではライブラリを検索できない!

–編集画面の「 Use Library」で名前を検索できるのが唯一の検索手段

• 今後の発展を祈ります。

Page 27: Jetpack Library 事始め

参考にすべきライブラリ• addon-kit• api-utils

• 本家の API がつい最近までコロコロ変わっていたので、サードパーティで十分な品質のライブラリはまだできていない(と予想。なにぶん検索できないのでよくわかりませんが)。

• ベータ版が出て、 API が固まりつつある今が参入時?

Page 28: Jetpack Library 事始め

ライブラリ例

Page 29: Jetpack Library 事始め

ロケーションバーアイコン API

• ロケーションバーの中にアイコンを表示する API を作ってみる

Page 30: Jetpack Library 事始め

API 設計• パッケージ名 : location-bar• モジュール名 : location-bar• クラス名 : Icon– コンストラクタ : label, tooltip, contentURL,

onClick– プロパティ : なし

Page 31: Jetpack Library 事始め

使い方const locationBar = require("location-bar");const tabs = require("tabs");

locationBar.Icon({ label: "Mozilla website", contentURL: "http://www.mozilla.org/favicon.ico", onClick: function() { tabs.open("http://www.mozilla.org/"); }});locationBar.Icon({ label: "Google website", contentURL: "http://www.google.com/favicon.ico", onClick: function() { tabs.open("http://www.google.com/"); }});

Page 32: Jetpack Library 事始め

動作• アイコン追加時:– 全てのウィンドウにアイコンを追加する

• アイコン削除時:– 全てのウィンドウからアイコンを削除する

• ウィンドウ追加時:– ウィンドウに全てのアイコンを追加する

• ウィンドウ削除時、拡張アンロード時:– ウィンドウから全てのアイコンを削除する

Page 33: Jetpack Library 事始め

コンストラクタ:オプションチェック

const apiUtils = require("api-utils");const { EventEmitter } = require("events");const windowUtils = require("window-utils");

var icons = [];

exports.Icon = EventEmitter.compose({ constructor: function Icon(options) { options = apiUtils.validateOptions(options, { label: { is: ["string"] }, tooltip: { is: ["null", "undefined", "string"] }, contentURL: { is: ["string"] }, onClick: { is: ["null", "undefined", "function"] } });

Page 34: Jetpack Library 事始め

コンストラクタ:初期化 this.id = "locationbaricon:" + require("xpcom").makeUuid().toString(); this._label = options.label; this.tooltip = ("tooltip" in options) ? options.tooltip : this._label this.contentURL = options.contentURL; if ("onClick" in options) { this.on("click", options.onClick); } icons.push(this); for (window in windowUtils.windowIterator()) { addItem(window, this); } },

Page 35: Jetpack Library 事始め

destroy destroy : function(){ var idx = icons.indexOf(this); if (idx > -1) { icons.splice(idx, 1); } for (window in windowUtils.windowIterator()) { removeItem(window, this); } }});

Page 36: Jetpack Library 事始め

アイコンの追加function addItem(window, icon) { var doc = window.document; var urlbar = doc.getElementById('urlbar'); if(urlbar) { var button = doc.createElement('toolbarbutton'); button.setAttribute("id", icon.id); button.setAttribute("tooltiptext", icon.tooltip); button.style.listStyleImage = 'url(' + icon.contentURL + ')'; button.addEventListener('click', function() icon._emit('click'), false); var goButton = doc.getElementById('urlbar-go-button'); urlbar.insertBefore(button, goButton); }}

Page 37: Jetpack Library 事始め

アイコンの削除function removeItem(window, icon) { var doc = window.document; var urlbar = doc.getElementById('urlbar'); if(urlbar) { var button = doc.getElementById(icon.id); urlbar.removeChild(button); }}

Page 38: Jetpack Library 事始め

ウィンドウの監視var windowManager = { init: function () { var windowTracker = new (windowUtils.WindowTracker)(this); require("unload").ensure(windowTracker); }, onTrack: function (window) { for(var i=0; i<icons.length; i++){ addItem(window, icons[i]); } }, onUntrack: function (window) { for(var i=0; i<icons.length; i++){ removeItem(window, icons[i]); } }}windowManager.init();

Page 39: Jetpack Library 事始め

まとめ• 自作ライブラリを作ることによっ

て、 Jetpack の可能性は大きく広がる。• XUL の構造まで把握できる人がライブラ

リを作り、一般開発者の人がそのライブラリを活用してサクッと拡張を開発する、といった分担ができるようになることを期待します。

Page 40: Jetpack Library 事始め

Thank you!