Nov 10, 2010
Jetpackを読み解く
Developers Conferenceでの発表向けの内容に盛り込めそうにない話を書いていく。
話のテーマを決めるにあたって、とにかく最初は1つJetpack SDKでアドオンを書いてみようと思ったんですよ。
でも、「こう書くと動きますよ」って言われてもなんだか信じられなかったというか、どういう経路でどういう風にしてそのコードが読み込まれるのか分からなくて、スクリプトの書き方次第じゃ他のコードに悪影響を及ぼしたりすることもあるんじゃないのか?(prototoype.jsのObject汚染みたいな感じで)とか、名前空間の衝突は大丈夫なのか? とか、そういうどーでもいい所が気になって気になって、仕組みが分からないまま使うのは怖いと思った。何をやってよくて、何をやったら駄目なのか、というのが分からないのが怖かった。
その境目を見極めたくて、Jetpack自体の成り立ちを探ってみたのですよ。
特に謎だったのが、他のモジュールを読み込むrequire()
。これが一体どこで処理されているのか。main.js(Jetpackでアドオンを作る時の主たる実装になるファイルの固定の名前)もどこかからrequire()
されているのなら、require()
の実装を見たら謎が解けるんじゃないかなーと思った。
- 核になるのは packages/jetpack-core/lib/securable-module.js の内容。Jetpackで頻出の
exports
やrequire()
はここで定義されている。- コードを見ると、CommonJS風のやり方だけでなく、JataScriptコードモジュール形式の書き方(
EXPORTED_SYMBOLS
を使うやり方)にも対応してるみたい。
- コードを見ると、CommonJS風のやり方だけでなく、JataScriptコードモジュール形式の書き方(
- コードを追っていくと、最終的に
Components.utils.evalInSandbox()
が呼ばれていることが分かった。ライブラリのモジュールもmain.jsも全部これで実行される。- ということで、JavaScriptの名前空間の中での事に関してはどんな無茶をしても大丈夫そうという事が分かった。
- もうひとつ、packages/jetpack-core/lib/cuddlefish.js も重要っぽい。
- Jetpack自体の組み込みのライブラリでしょっちゅう使われてるユーティリティっぽいモジュールであるところの
require("chrome")
の実態が、これ。 - Cuddlefish Labというアドオンの形で導入することもできるみたい?
- Labs/Jetpack/JEP/28に、詳しい事が書かれてる。
- Jetpack自体の組み込みのライブラリでしょっちゅう使われてるユーティリティっぽいモジュールであるところの
Jetpackとは、この基本的な仕組みに基づいて、個々のモジュールの名前空間を分け、それらを安全に連携できるようにしたもの。と言える。MozLabでmodule_manager.jsというものが過去に使われていて、それを想起させられた。
module_manager.jsはJavaScriptコードモジュールが無かった頃にJavaScriptそのものの言語仕様を超えた所で高度なモジュール化を行おうとしていたらしく、渡されたモジュールの名前からパスを生成してファイルを読み込んでサンドボックス内で実行してそのグローバルオブジェクトを保持し続けて……ということを普通のJavaScriptの機能とmozIJSSubScriptLoaderでやってた。Jetpackの仕組みはそれのずっとスマートなバージョンなのかなと思った。
今までの開発手法しか知らなくてJetpackがさっぱり分からないという僕みたいな時代後れの人でも、securable-module.jsとcuddlefish.jsを起点にすれば、他のモジュールも無理なく読んでいけるんじゃないだろうか。
wikieditish message: Ready to edit this entry.