RequireJS使い方メモ

未だにモジュール管理してないので、基本っぽい RequireJS を勉強する。

#RequireJS とは
JavaScript 用のモジュール管理フレームワークの１つ。

JavaScript を実装していて、 view や model などで細かくファイルを分割していると、ファイル間の依存関係を意識して読み込む順序を注意しないといけなくなる。
（`<script>` タグの読み込み順序を調整するか、もしくはコンカチしているのであれば、そのコンカチ順序を管理しないといけない）

ファイル数が少なかったり、個人で開発しているのであれば手動管理でも大きな問題はない。
しかし、ファイル数が多くなってきたり複数人で開発していると、手動管理では限界がある。

RequireJS では、 JavaScript のコードを**モジュール**という単位で管理する。
そして、各コードは実装の先頭で使用するモジュールを宣言する。

RequireJS は使用するモジュールの宣言を元に、各モジュール間の依存関係を調べ、適切な順序で JavaScript のコードを読み込むようにしてくれる（`<script> タグが自動で HTML に埋め込まれる`）。

#Hello World
##RequireJSのインストール
[Download RequireJS](http://requirejs.org/docs/download.html)

`require.js` をダウンロードする。

##実装
```html:sample.html
<!DOCTYPE html>
<html>
  <head>
    <script data-main="main.js" src="require.js"></script>
  </head>
  <body>
  </body>
</html>
```

```js:util.js
define(function() {
    return {
        add: function(a, b) {
            return a + b;
        }
    };
});
```

```js:main.js
require(['util'], function(util) {
    var result = util.add(10, 21);
    console.log('10 + 21 = ' + result);
});
```

```text:フォルダ構成
|-sample.html
|-main.js
|-util.js
`-require.js
```

##動作確認
`sample.html` をブラウザで開く。

```text:コンソール出力
10 + 21 = 31
```

##説明
- `<script>` タグを使って `require.js` を読み込む。
    - このとき、 `data-main` 属性でそのページで読み込むメインの JavaScript ファイルを指定する。
- モジュールの定義は、 `define()` 関数を使用する（`util.js`）。
    - 引数には関数を渡し、戻り値に定義するモジュールのオブジェクトを返すようにする。
- モジュールを使用する側は、 `require()` 関数を使って依存するモジュールを解決する。
    - 第一引数に使用するモジュールの名前を配列で渡す。
    - モジュールの名前は、 JavaScript ファイルの名前に一致させる（拡張子は省略）。
    - 第二引数に、依存モジュールを受け取って処理を実行する関数を渡す。
    - 関数の引数には、第一引数で指定したモジュールの実体が渡される。
        - 順序が一致していれば、変数名は違っていても良い。

#関数をモジュール化する
```js:minus.js
define(function() {
    return function(a, b) {
        return a - b;
    };
});
```

```js:main.js
require(['minus'], function(minus) {
    var result = minus(22, 14);
    console.log('22 - 14 = ' + result);
});
```

```text:フォルダ構成
|-sample.html
|-main.js
|-minus.js
`-require.js
```

```text:コンソール出力
22 - 14 = 8
```

- `define()` で関数を返せば、関数単独でモジュール化できる。

#複数の依存関係を指定する
##基本
```js:main.js
require(['util', 'minus'], function(util, minus) {
    console.log('14 + 51 = ' + util.add(14, 51));
    console.log('22 - 14 = ' + minus(22, 14));
});
```

```text:フォルダ構成
|-sample.html
|-main.js
|-minus.js
|-util.js
`-require.js
```

```text:コンソール出力
14 + 51 = 65
22 - 14 = 8
```

##require() 関数で依存対象を取得する
```main.js
define(function(require, exports, module) {
    var util = require('util');
    var minus = require('minus');

    console.log('14 + 51 = ' + util.add(14, 51));
    console.log('22 - 14 = ' + minus(22, 14));
});
```

```text:フォルダ構成
|-sample.html
|-main.js
|-minus.js
|-util.js
`-require.js
```

```text:コンソール出力
14 + 51 = 65
22 - 14 = 8
```

- 依存対象が増えてくると、引数の数が多くなって大変なので、その場合は `require()` 関数を使って依存対象を取得する方法がある。

#依存対象のファイルがサブフォルダに存在する場合
```text:フォルダ構成
|-sample.html
`-js/
  |-main.js
  |-lib/
  |  `-require.js
  `-app/
     |-util.js
     `-minus.js
```

```html:sample.html
<!DOCTYPE html>
<html>
  <head>
    <script data-main="js/main.js" src="js/lib/require.js"></script>
  </head>
  <body>
  </body>
</html>
```

```js:main.js
require(['app/util'], function(util) {
    var result = util.add(1, 23);

    console.log('1 + 23 = ' + result);
});
```

```text:コンソール出力
1 + 23 = 24
```

- `<script>` タグの `data-main` 属性は、その HTML からのパスを指定する（`js/main.js`）。
- `require()` で依存対象を解決するときに指定するパスは、その JavaScript ファイルからのパスを指定する（`app/util`）。
    - 厳密には、 `baseUrl` という設定値で指定した場所からのパスを指定するが、 `data-main` 属性で起点となるソースを指定している場合は、そのファイルが存在する場所が `baseUrl` になる。

#パスの指定を省略できるようにする
```text:フォルダ構成
|-sample.html
`-js/
  |-main.js
  |-require_config.js
  |-lib/
  |  `-require.js
  `-app/
     |-util.js
     `-minus.js
```

```html:sample.html
<!DOCTYPE html>
<html>
  <head>
    <script src="js/require_config.js"></script>
    <script data-main="js/main.js" src="js/lib/require.js"></script>
  </head>
  <body>
  </body>
</html>
```

```js:require_config.js
var require = {
    paths: {
        'util': 'app/util'
    }
};
```

```js:main.js
require(['util'], function(util) {
    var result = util.add(13, 42);

    console.log('13 + 42 = ' + result);
});
```

- `require` という名前のグローバル変数を定義し、そこに設定を定義したオブジェクトを代入する。
    - この定義を、 `require.js` が読み込まれる前に実行する。
    - `require.js` が読み込まれた後で定義する場合は、 `requirejs.config()` という関数を使用する。
- `paths` プロパティで、依存対象ごとにパスの省略形を定義する。
- パスは、 `baseUrl` から見たときのパスで指定する（`data-main` で起点となるソースを読み込んでいるので、そのファイルが存在する場所が `baseUrl` になる）。

#AMD 形式に対応しているライブラリを使用する
jQuery(1.7 以上) や Underscore.js(1.6.0 以上) は AMD 形式に対応しているので、簡単に使える。

```text:フォルダ構成
|-sample.html
`-js/
  |-main.js
  |-require_config.js
  `-lib/
     |-underscore-min.js
     |-jquery.min.js
     `-require.js
```

```js:require_config.js
var require = {
    paths: {
        'underscore': 'lib/underscore-min',
        'jquery': 'lib/jquery.min'
    }
};
```

```js:main.js
require(['jquery', 'underscore'], function($, _) {
    $(function() {
        var array = [1, 2, 3, 4, 5];

        var $ul = $('<ul />');

        _.each(array, function(i, n) {
            $ul.append('<li>' + n + '</li>');
        });

        $('body').append($ul);
    });
});
```



#AMD 形式に対応していないライブラリを使用する
使おうとしているライブラリが、 `define()` を使ってモジュールを定義していれば、そのまま RequreJS で使用できる。
しかし、それに対応していないライブラリを使う場合は、以下のように設定する。

```text:フォルダ構成
|-sample.html
`-js/
  |-main.js
  |-require_config.js
  `-lib/
     |-underscore-min.js
     |-non-amd-lib.js
     `-require.js
```

```js:non-amd-lib.js
var mine = {
    addAll: function(array) {
        var sum = _.reduce(array, function(memo, n) {
            return memo + n;
        }, 0);

        return sum;
    }
};
```

```js:require_config.js
var require = {
    shim: {
        'lib/non-amd-lib': {
            deps: ['lib/underscore-min'],
            exports: 'mine'
        }
    }
};
```

```js:main.js
require(['lib/non-amd-lib'], function(nonAmdLib) {
    var result = nonAmdLib.addAll([10, 12, 32, 21]);

    console.log('10 + 12 + 32 + 21 = ' + result);
});
```

```text:コンソール出力
10 + 12 + 32 + 21 = 75
```

- `shim` で AMD に対応していないライブラリについての定義を記述する。
- キー（`lib/non-amd-lib`）で、使用するライブラリのソースのパスを指定する。
- `deps` で、そのライブラリが依存している他のライブラリを指定する（`lib/underscore-min`）。
- `exports` で、そのライブラリがグローバル変数として定義しているオブジェクトの名前を指定する（`mine`）。
    - `require()` による依存関係の解決のときには、ここで指定したオブジェクトが渡されることになる。

##paths 設定と組み合わせる
```js:require_config.js
var require = {
    paths: {
        'underscore': 'lib/underscore-min',
        'nonAmdLib': 'lib/non-amd-lib'
    },
    
    shim: {
        'nonAmdLib': {
            deps: ['underscore'],
            exports: 'mine'
        }
    }
};
```

```js:main.js
require(['nonAmdLib'], function(nonAmdLib) {
    var result = nonAmdLib.addAll([10, 12, 32, 21]);

    console.log('10 + 12 + 32 + 21 = ' + result);
});
```

#コードを１つにまとめる
r.js という専用ツールを使ってソースをまとめる。
r.js は npm でインストールし、 Node.js 上で動くので、 Node.js をあらかじめインストールしておく（割愛）。

##r.js のインストール
```text:
> npm install -g requirejs
```

```text:確認
> r.js.cmd -v
r.js: 2.1.15, RequireJS: 2.1.15, UglifyJS2: 2.4.13, UglifyJS: 1.3.4
```

- Windows 環境では、 `r.js.cmd` で起動する。

##簡単な例
```text:フォルダ構成
|-sample.html
|-require.js
|-main.js
`-util.js
```

```js:util.js
define(function() {
    return {
        add: function(a, b) {
            return a + b;
        }
    };
});
```

```js:main.js
require(['util'], function(util) {
    var result = util.add(20, 31);
    
    console.log('20 + 31 = ' + result);
});
```

##r.js でファイルを１つにまとめる
```text:
> r.js.cmd -o name=main out=built.js 
```

- `-o` の後ろに設定を記述する。
- `name` は、起点となるファイルを指定（`data-main` 属性で指定してたファイル）。
- `out` は、出力するファイル。

```js:built.js
define("util",[],function(){return{add:function(e,t){return e+t}}}),require(["util"],function(e){var t=e.add(20,31);console.log("20 + 31 = "+t)}),define("main",function(){});
```

コンカチ＋ minify されたファイルが出力される。

##生成されたファイルを使う
```html:sample.html
<!DOCTYPE html>
<html>
  <head>
    <script data-main="built" src="require.js"></script>
  </head>
  <body>
  </body>
</html>
```

```text:コンソール出力
20 + 31 = 51
```

- `data-main` 属性に生成されたファイルを指定すえれば、これまで通りに使える。

#paths や shim を使っている場合
##実装
```text:フォルダ構成
|-sample.html
`-js/
  |-main.js
  `-lib/
    |-non-amd-lib.js
    |-require.js
    `-underscore-min.js
```

```js:non-amd-lib.js
var mine = {
    addAll: function(array) {
        var sum = _.reduce(array, function(memo, n) {
            return memo + n;
        }, 0);

        return sum;
    }
};
```

```js:main.js
require(['nonAmdLib'], function(nonAmdLib) {
    var result = nonAmdLib.addAll([1, 41, 30, 57]);

    console.log('1 + 41 + 30 + 57 = ' + result);
});
```

##設定ファイルを用意する
```js:rjs_config.js
({
    baseUrl: 'js',
    name: 'main',
    out: 'js/built.js',
    paths: {
        'underscore': 'lib/underscore-min',
        'nonAmdLib': 'lib/non-amd-lib'
    },
    shim: {
        'nonAmdLib': {
            deps: ['underscore'],
            exports: 'mine'
        }
    }
})
```

- コマンドラインで指定できるけど、ここまで多くなると設定ファイルに定義した方がいい。

##r.js コマンドでまとめる
```text:
> r.js.cmd -o rjs_config.js
```

`js/built.js` に出力される。

##生成されたファイルを使う
```html:sample.html
<!DOCTYPE html>
<html>
  <head>
    <script data-main="js/built" src="require.js"></script>
  </head>
  <body>
  </body>
</html>
```

```text:コンソール出力
1 + 41 + 30 + 57 = 129
```


#参考
- [JavaScript - AMD & RequireJS - Qiita](http://qiita.com/nanocitrus/items/70f1316debf05b93ac82)
- [2011-11-06のJS: jQuery 1.7リリース、AMD&モジュール化、Chrome Developer Tools - JSer.info](http://jser.info/post/12412054655/)
- [RequireJSを始めて戸惑ったこと - orangain flavor](http://orangain.hatenablog.com/entry/getting-started-with-requirejs)