未だにモジュール管理してないので、基本っぽい RequireJS を勉強する。
#RequireJS とは
JavaScript 用のモジュール管理フレームワークの1つ。
JavaScript を実装していて、 view や model などで細かくファイルを分割していると、ファイル間の依存関係を意識して読み込む順序を注意しないといけなくなる。
(<script>
タグの読み込み順序を調整するか、もしくはコンカチしているのであれば、そのコンカチ順序を管理しないといけない)
ファイル数が少なかったり、個人で開発しているのであれば手動管理でも大きな問題はない。
しかし、ファイル数が多くなってきたり複数人で開発していると、手動管理では限界がある。
RequireJS では、 JavaScript のコードをモジュールという単位で管理する。
そして、各コードは実装の先頭で使用するモジュールを宣言する。
RequireJS は使用するモジュールの宣言を元に、各モジュール間の依存関係を調べ、適切な順序で JavaScript のコードを読み込むようにしてくれる(<script> タグが自動で HTML に埋め込まれる
)。
#Hello World
##RequireJSのインストール
Download RequireJS
require.js
をダウンロードする。
##実装
<!DOCTYPE html>
<html>
<head>
<script data-main="main.js" src="require.js"></script>
</head>
<body>
</body>
</html>
define(function() {
return {
add: function(a, b) {
return a + b;
}
};
});
require(['util'], function(util) {
var result = util.add(10, 21);
console.log('10 + 21 = ' + result);
});
|-sample.html
|-main.js
|-util.js
`-require.js
##動作確認
sample.html
をブラウザで開く。
10 + 21 = 31
##説明
-
<script>
タグを使ってrequire.js
を読み込む。- このとき、
data-main
属性でそのページで読み込むメインの JavaScript ファイルを指定する。
- このとき、
- モジュールの定義は、
define()
関数を使用する(util.js
)。- 引数には関数を渡し、戻り値に定義するモジュールのオブジェクトを返すようにする。
- モジュールを使用する側は、
require()
関数を使って依存するモジュールを解決する。- 第一引数に使用するモジュールの名前を配列で渡す。
- モジュールの名前は、 JavaScript ファイルの名前に一致させる(拡張子は省略)。
- 第二引数に、依存モジュールを受け取って処理を実行する関数を渡す。
- 関数の引数には、第一引数で指定したモジュールの実体が渡される。
- 順序が一致していれば、変数名は違っていても良い。
#関数をモジュール化する
define(function() {
return function(a, b) {
return a - b;
};
});
require(['minus'], function(minus) {
var result = minus(22, 14);
console.log('22 - 14 = ' + result);
});
|-sample.html
|-main.js
|-minus.js
`-require.js
22 - 14 = 8
-
define()
で関数を返せば、関数単独でモジュール化できる。
#複数の依存関係を指定する
##基本
require(['util', 'minus'], function(util, minus) {
console.log('14 + 51 = ' + util.add(14, 51));
console.log('22 - 14 = ' + minus(22, 14));
});
|-sample.html
|-main.js
|-minus.js
|-util.js
`-require.js
14 + 51 = 65
22 - 14 = 8
##require() 関数で依存対象を取得する
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));
});
|-sample.html
|-main.js
|-minus.js
|-util.js
`-require.js
14 + 51 = 65
22 - 14 = 8
- 依存対象が増えてくると、引数の数が多くなって大変なので、その場合は
require()
関数を使って依存対象を取得する方法がある。
#依存対象のファイルがサブフォルダに存在する場合
|-sample.html
`-js/
|-main.js
|-lib/
| `-require.js
`-app/
|-util.js
`-minus.js
<!DOCTYPE html>
<html>
<head>
<script data-main="js/main.js" src="js/lib/require.js"></script>
</head>
<body>
</body>
</html>
require(['app/util'], function(util) {
var result = util.add(1, 23);
console.log('1 + 23 = ' + result);
});
1 + 23 = 24
-
<script>
タグのdata-main
属性は、その HTML からのパスを指定する(js/main.js
)。 -
require()
で依存対象を解決するときに指定するパスは、その JavaScript ファイルからのパスを指定する(app/util
)。- 厳密には、
baseUrl
という設定値で指定した場所からのパスを指定するが、data-main
属性で起点となるソースを指定している場合は、そのファイルが存在する場所がbaseUrl
になる。
- 厳密には、
#パスの指定を省略できるようにする
|-sample.html
`-js/
|-main.js
|-require_config.js
|-lib/
| `-require.js
`-app/
|-util.js
`-minus.js
<!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>
var require = {
paths: {
'util': 'app/util'
}
};
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 形式に対応しているので、簡単に使える。
|-sample.html
`-js/
|-main.js
|-require_config.js
`-lib/
|-underscore-min.js
|-jquery.min.js
`-require.js
var require = {
paths: {
'underscore': 'lib/underscore-min',
'jquery': 'lib/jquery.min'
}
};
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 で使用できる。
しかし、それに対応していないライブラリを使う場合は、以下のように設定する。
|-sample.html
`-js/
|-main.js
|-require_config.js
`-lib/
|-underscore-min.js
|-non-amd-lib.js
`-require.js
var mine = {
addAll: function(array) {
var sum = _.reduce(array, function(memo, n) {
return memo + n;
}, 0);
return sum;
}
};
var require = {
shim: {
'lib/non-amd-lib': {
deps: ['lib/underscore-min'],
exports: 'mine'
}
}
};
require(['lib/non-amd-lib'], function(nonAmdLib) {
var result = nonAmdLib.addAll([10, 12, 32, 21]);
console.log('10 + 12 + 32 + 21 = ' + result);
});
10 + 12 + 32 + 21 = 75
-
shim
で AMD に対応していないライブラリについての定義を記述する。 - キー(
lib/non-amd-lib
)で、使用するライブラリのソースのパスを指定する。 -
deps
で、そのライブラリが依存している他のライブラリを指定する(lib/underscore-min
)。 -
exports
で、そのライブラリがグローバル変数として定義しているオブジェクトの名前を指定する(mine
)。-
require()
による依存関係の解決のときには、ここで指定したオブジェクトが渡されることになる。
-
##paths 設定と組み合わせる
var require = {
paths: {
'underscore': 'lib/underscore-min',
'nonAmdLib': 'lib/non-amd-lib'
},
shim: {
'nonAmdLib': {
deps: ['underscore'],
exports: 'mine'
}
}
};
require(['nonAmdLib'], function(nonAmdLib) {
var result = nonAmdLib.addAll([10, 12, 32, 21]);
console.log('10 + 12 + 32 + 21 = ' + result);
});
#コードを1つにまとめる
r.js という専用ツールを使ってソースをまとめる。
r.js は npm でインストールし、 Node.js 上で動くので、 Node.js をあらかじめインストールしておく(割愛)。
##r.js のインストール
> npm install -g requirejs
> 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
で起動する。
##簡単な例
|-sample.html
|-require.js
|-main.js
`-util.js
define(function() {
return {
add: function(a, b) {
return a + b;
}
};
});
require(['util'], function(util) {
var result = util.add(20, 31);
console.log('20 + 31 = ' + result);
});
##r.js でファイルを1つにまとめる
> r.js.cmd -o name=main out=built.js
-
-o
の後ろに設定を記述する。 -
name
は、起点となるファイルを指定(data-main
属性で指定してたファイル)。 -
out
は、出力するファイル。
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 されたファイルが出力される。
##生成されたファイルを使う
<!DOCTYPE html>
<html>
<head>
<script data-main="built" src="require.js"></script>
</head>
<body>
</body>
</html>
20 + 31 = 51
-
data-main
属性に生成されたファイルを指定すえれば、これまで通りに使える。
#paths や shim を使っている場合
##実装
|-sample.html
`-js/
|-main.js
`-lib/
|-non-amd-lib.js
|-require.js
`-underscore-min.js
var mine = {
addAll: function(array) {
var sum = _.reduce(array, function(memo, n) {
return memo + n;
}, 0);
return sum;
}
};
require(['nonAmdLib'], function(nonAmdLib) {
var result = nonAmdLib.addAll([1, 41, 30, 57]);
console.log('1 + 41 + 30 + 57 = ' + result);
});
##設定ファイルを用意する
({
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 コマンドでまとめる
> r.js.cmd -o rjs_config.js
js/built.js
に出力される。
##生成されたファイルを使う
<!DOCTYPE html>
<html>
<head>
<script data-main="js/built" src="require.js"></script>
</head>
<body>
</body>
</html>
1 + 41 + 30 + 57 = 129
#参考