r.jsでビルドする際に設定として使うbuild.jsを動的にする。さらに部品化する。

r.js

RequireJS用のmoduleをビルドする際にはr.jsを使います。

build.js

この時にビルド設定の記述に使用するのがbuild.jsでこんな感じで書きます。
簡単な例だとこんなの

({
  baseUrl:'./src',
  dir : './build',
  paths:{
    jquery:"../lib/jquery-1.8.2",
    text:'../lib/plugins/text',
    underscore:'../lib/underscore-1.3.3'
  }
})

動的なbuild.js

build.jsはJSONではなくてJSです。
JSなので処理を書くことが出来ます。
例えば関数その場実行を含む下記のbuild.jsは、上記のものと同じ設定を表します。

({
  baseUrl:'./src',
  dir : './build',
  paths:(function () {
    var paths = {
      jquery:"../lib/jquery-1.8.2",
      text:'../lib/plugins/text',
      underscore:'../lib/underscore-1.3.3'
    };
    return paths;
  })()
})

ちなみに全体を関数その場実行で包むことは出来ません。
以下のコードはbuild.jsとしては使えません。

(function () {
  return ({
    baseUrl:'./src',
    dir : './build',
    paths:{
      jquery:"../lib/jquery-1.8.2",
      text:'../lib/plugins/text',
      underscore:'../lib/underscore-1.3.3'
    }
  });
})();

さて、現状ではbuild.jsの中に処理を書けるようになったものの、何を以て設定を変更するかが分からないので、動的というほどではなくてあまり嬉しくありません。
r.jsはNode.jsで実行されているので、process.argvでコマンドライン引数を参照することも出来ます。

r.js -o build.js optimize='none' os='ios5'
({
  baseUrl:'./src',
  dir : './build',
  paths:(function () {
    var paths = {
      jquery:"../lib/jquery-1.8.2",
      text:'../lib/plugins/text',
      underscore:'../lib/underscore-1.3.3'
    };
    var os = (process.argv.filter(function (arg) {
      return arg.match(/^os=/);
    })[0] || '').replace(/^os=/,'');
    if (os === 'ios5') {
      // 何らかの処理
    }
    return paths;
  })()
})

これでコマンドラインオプションによってビルド時の設定を細かく変えることが出来るようになりました。

build.jsのNode.js module化

繰り返しますが全体を関数その場実行で包むことは出来ません。
objectのvalueしか関数その場実行で包めません。
つまり、処理を関数として共通化したくても、それを置いておく場所がありません。
例えば各項目でos optionによる振り分けを行いたいなら、各項目のvalueの関数その場実行の中に以下を入れる必要があります。

    var os = (process.argv.filter(function (arg) {
      return arg.match(/^os=/);
    })[0] || '').replace(/^os=/,'');

これではちょっとやりたいことが増えればすぐに肥大化してしまいます。

さて、繰り返しますがr.jsはNode.jsで実行されています。共通化したい処理はNode.jsのmoduleにしてしまいましょう。
以下のような内容のoptions.jsを作ります。

var os = (process.argv.filter(function (arg) {
  return arg.match(/^os=/);
})[0] || '').replace(/^os=/,'');
module.exports = function options(){
  return {
    os:os
  }
};

これを使う際の注意点は二つあります。

  • Node.jsのmodule読み込み関数requireはr.jsではrequire.jsのそれで上書きされています。
    • nodeRequireが元々のrequire関数なのでこれを使います。
  • Node.jsで実行されているのはr.jsなので、build.jsからの相対pathでmoduleを読み込もうとしても無駄です。
    • process.env.PWDを使ってr.jsを実行したときのカレントディレクトリ(build.jsはここにある前提)を参照しましょう。

こんな感じでもりもりbuild.jsを動的にしていくことが出来ます。
複数環境向けビルドをしたいとか行った場合に捗りますね。

({
  baseUrl:'./src',
  dir : './build',
  paths:(function () {
    var paths = {
      jquery:"../lib/jquery-1.8.2",
      text:'../lib/plugins/text',
      underscore:'../lib/underscore-1.3.3'
    };
    var options = nodeRequire(process.env.PWD+'/build-tools/options')();
    var os = options['os'];
    if (os === 'ios5') {
      // 何らかの処理
    }
    return paths;
  })()
})