requireでTitaniumのインクルードパスの問題を解決する

Ti.includeじゃなくてrequireを使うと幸せになれるっぽい。
CommonJSでJavaScirptのモジュールを定義することになるので、Ti.includeをそのまま置き換えることはできないけど。

これで黒魔術とおさらばできるかしら。

実験

app.js
var window = Ti.UI.createWindow({ url: "lib/hoge.js" });
window.open();

Ti.includeとは違うところを確認するためにlib以下のurlを指定したウィンドウを開く。

lib/hoge.js
var hoge = require("lib/fuga");
hoge.foo();

lib/fuga.jsのrequireを行う。

Resourcesからの相対パスで指定できているところに注目。
Ti.includeで同じような指定をすると

Ti.include("lib/fuga.js");

Resources/lib/lib/fuga.jsを探してエラーになる。

lib/fuga.js
exports.foo = function() {
    alert("hagehage");
};

読み込むファイルはCommonJS準拠のモジュールにする。
exportsしたものが外部から利用できるようになる。

うつくしい。

クラスをモジュールにしてrequire

1クラス1ファイルでコードを書いていた場合、クラスをまるごとexportsすればあまり修正しなくてもTi.includeから置き換えられる。

lib/class_a.js
ClassA = function(){};
ClassA.prototype.foo = function() {
    alert("hogehoge");
};

exports.ClassA = ClassA;

最後の一行を追加。
exports = ClassAとは書けない。

lib/hoge.js
var ClassA = require("lib/class_a").ClassA;
var hoge = new ClassA();
hoge.foo();

requireのおしりにClassAを忘れずに。

モジュール自体をクラス的に使う

こともできる。
むしろこちらの使い方の方がポピュラー?

lib/module_a.js
exports = {
  setMessage: function(message){ this.message = message },
  foo: function() { alert(this.message); }
};

同じモジュールを複数回requireしてもそれぞれ別オブジェクトということを確認するためにalertで表示する内容をセットできるようにしてみた。

あとexportsと何度も書くのがめんどくさいのでオブジェクトにまとめて渡してみるなど。

lib/hoge.js
var hogeA = require("lib/module_a");
hogeA.setMessage("HOGE!");

var hogeB = require("lib/module_a");
hogeB.setMessage("HOGEHOGE!");

hogeA.foo();
hogeB.foo();

実行するときちんと別のオブジェクトになっていることが確認できる。

メモ

urlやimageのパス指定について

Ti.includeと違ってもともと黒魔術は必要ない。

var window = Ti.UI.createWindow({ url: Ti.Filesystem.resourcesDirectory + "/lib/window.js" });
var imageView = Ti.UI.createImageView({image: Ti.Filesystem.resourcesDirectory + "/images/hoge.png"});

よってTi.includeさえ使わないですむようになれば黒魔術とはおさらばできる。

CommonJSとrequireについて

CommonJS準拠のモジュールをいろいろ読み込めるというのは面白いかも。
ところでObjective-CやJavaで書くモジュールと紛らわしいけど、こっちもモジュールという呼び方でいいのかな。

require.pathsは残念ながら使えない。
もともとundefinedで、自分で定義してやっても使えなかった。

参考

CommonJS関連

まだイマイチCommonJSを把握できていません。

2011/07/24追記

この情報は古いです。
MobileSDK1.7からiOSでもTi.includeのファイル指定を絶対パスでできるようになったので、この技で解決していた問題はなくなりました。
またAndroidではもともとTi.includeの問題はなく、かつこの技は使えなかったようです。

そういう訳でrequireはモジュールを読むときだけ使うのが現状ではいいのかなと思います。

2011/08/11追記

やっぱCommonJSスタイル推奨らしい。
Forging Titanium Episode 1: CommonJS Modules

Android実機では書き方次第でrequireが動いたり動かなかったりという情報を耳にした。
現状どうなっているのかはテストしてみないと分からないなー。

requireでTitaniumのインクルードパスの問題を解決する” に対して2件のコメントがあります。

コメントは受け付けていません。