file i/o #10: final!

Opera をはじめ、Chrome と Firefox でも dropbox に対する読み書きを行えるようにした。

Chrome でも動くようにするのは、ぜんぜん難しくないのだ。んが、Firefox で動かすのがなかなか面倒。他のブラウザが、エクステンションといいつつも実態は html ページなのに対して、Firefox (Add-on SDK) で動くエクステンションのコードというのはグローバルオブジェクトが [object Proxy] だかなんだかという見慣れた window とはちょっと違う何かだったりする。

で、jsOAuth.js という独立したライブラリを参照する際、Opera と Chrome ではスタートアップとなる html ページにいつものよーに script 要素を書くだけでよいのだが、Firefox の場合は CommonJS に従ったルールで lib ディレクトリに置く必要がある。jsOAuth は Node.js & CommonJS コンパチブルだと謳っているので、まあ Firefox でもうまくいけばそのまま動くのだろうなどと思っていたら、甘かった。

CommonJS に則った方式で再利用可能なモジュールを書く場合、

exports.foo = function () {
console.log('hello, world');
};

などと exports に対して登録する形になる。jsOAuth もその先頭で

var exports = exports || this;
exports.OAuth = (function (global) {
:
})(this);

とやっている。これで、CommonJS 下ではエクスポート、一般的な javascript では window に OAuth オブジェクトが結び付けられる。めでたしめでたし……のはずが、なぜか Firefox ではいくら再利用する側で

var OAuth = require('./jsOAuth');

とやっても読み込まれない。正確には、読み込まれるのだが(つまり jsOAuth.js 自体は評価されるのだが)、再利用できない。OAuth は undefined のままなのだ。

結論から書くと

typeof window == 'object' && eval('var exports = this;');
exports.OAuth = (function (global) {
:
})(this);

のようにする必要がある。SDK が提供する javascript の実行環境は前述の object Proxy だか sandbox だかの、管理された空間みたいなのだが、その空間のグローバルに提供される exports やら require() やらはちょっと特殊な扱いっぽいのだな。なのでおそらく、var exports なんてしちゃうと本来の exports を「管理された空間上の exports 」で覆ってしまって役に立たなくなるということなのだと思う。したがって、exports の polyfill を定義するのは本当に window 下で実行されているときだけに厳密に分けないといけない。

そもそも require とか exports とか、どこでどう定義されているのかと SDK のソースをいろいろ探ってみたのだけど、どうも見つけられなかったのは内緒。いやまあ packages/api-utils/lib/loader.js とか cuddlefish.js とかがキーだと思うんだけど……。なんか bootstrap から追っていってもいきなり require() とか使い出してる感じだしよく分からなかった。

このほか、XMLHttpRequest も SDK 専用品を使わなければならなかったり(しかも upload プロパティまだ実装してまへんテヘペロ とかいう未完成品だったりする)、Firefox はなかなかいろいろと勝手が違うのだった。

Leave a Reply

Your email address will not be published. Required fields are marked *