require.jsで、他のモジュールに依存するモジュールを、次の2つのような書き方で定義できる。(他にもある)
define(['a'], function(a){
// モジュールaがコールバックに渡ってくる
});
define(function(require){
// モジュールaをロード
var a = require("a");
})
下の書き方はなんとなく前から知ってたんだけど、クライアント側じゃ仕組み的に無理くね?と思ってたから、勘違いだと思ってた。
しかし下の書き方はできるのであった。同期っぽく読み込める。
a.js は非同期で読み込まれてるはずなのに、aに代入されてる。why?
ソースを覗いてみると。。
...
if (callback.length) {
callback
.toString()
.replace(commentRegExp, '')
.replace(cjsRequireRegExp, function (match, dep) {
deps.push(dep);
});
...
わーお、予めdefineが呼ばれた時点で、中身の関数を1度文字列にして、それを解析して読むべきモジュールを予めロードしていた。
というか、 require.jsのサイトにも書いてありましたね。
This wrapper relies on Function.prototype.toString() to give a useful string value of the function contents. This does not work on some devices like the PS3 and some older Opera mobile browsers. Use the optimizer to pull out the dependencies in the array format for use on those devices.
昔のOperaだと動かないらしい。optimizer(r.jsのこと?)をつかえば、配列でフォーマットされる方に変換されるとのこと。
Function.prototype.toString を使ってrequire関数を呼んでる場所を解析している関係で、以下のコードは動かないことに注意
define(function(require){
var superRequire = require;
var a = superRequire('a'); // モジュールはないと言われる
require = function(arg){ ... }
require("abcd"); // 意図せず abcd.js の読み込みが走る
})
require関数を使うほうが可読性が高いので、使っていこうと思う。