JavascriptはちょっとしたコードならHTMLに直接記述するのもいいのですが、大きくなると別ファイルにしてHTMLから分離する方が見通しがよくなります。さらにそのファイルが大きくなってくると分割して見通しを良くしたくなります。同時に、分割したものは部品としていろいろなプロジェクトに流用することも可能になります。
ただ、JSファイルを分割ロードする場合、その依存関係が問題になります。
jQueryを使った以下のコードをファイルに分割することを考えてみます。
index.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8" /> <script src="js/lib/jquery/jquery.js"></script> <script> (function($){ $.fn.alpha = function() { return this.append('<p>Alpha is Go!</p>'); }; $.fn.beta = function() { return this.append('<p>Beta is Go!</p>'); }; })(jQuery); $(function(){ $('body').alpha().beta(); }); </script> <title></title> </head> <body> <h1>Sample Page</h1> </body> </html> |
1.まずJavascriptコードを別ファイルに
index.html
1 2 3 4 5 6 7 8 9 10 11 12 |
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8" /> <script src="js/lib/jquery/jquery.js"></script> <script src="js/app/myapp.js"></script> <title></title> </head> <body> <h1>Sample Page</h1> </body> </html> |
js/app/myapp.js
1 2 3 4 5 6 7 8 9 10 11 12 |
(function($){ $.fn.alpha = function() { return this.append('<p>Alpha is Go!</p>'); }; $.fn.beta = function() { return this.append('<p>Beta is Go!</p>'); }; })(jQuery); $(function(){ $('body').alpha().beta(); }); |
Javascriptのコードを別ファイルに分離する前と同じ結果が得られます。
では、index.htmlでjQueryとjs/app/myapp.jsの位置を上下反対にするとどうでしょうか?
index.html
1 2 3 4 5 6 7 8 9 10 11 12 |
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8" /> <script src="js/app/myapp.js"></script> <script src="js/lib/jquery/jquery.js"></script> <title></title> </head> <body> <h1>Sample Page</h1> </body> </html> |
いままで表示されていた”Alpha is Go!”と”Beta is Go!”が表示されなくなります。
これは、jQueryのロードを完了する前にjQueryに依存するmyapp.jsをロードしたためです。ちなみに、chromeのデベロッパーツールでロードの様子をみると以下のとおりです。
上下入れ替え前
上下入れ替え後
2.続いて別ファイルにしたJSファイルを分割
HTMLから分離したJSファイルjs/app/myapp.jsを以下の3つのファイルに分割します。
js/app/alpha.js
1 2 3 4 5 |
(function($){ $.fn.alpha = function() { return this.append('<p>Alpha is Go!</p>'); }; })(jQuery); |
js/app/beta.js
1 2 3 4 5 |
(function($){ $.fn.beta = function() { return this.append('<p>Beta is Go!</p>'); }; })(jQuery); |
js/app/myapp.js
1 2 3 |
$(function(){ $('body').alpha().beta(); }); |
分割したJSファイルを呼び出すようにindex.htmlを編集します。
index.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8" /> <script src="js/lib/jquery/jquery.js"></script> <script src="js/app/alpha.js"></script> <script src="js/app/beta.js"></script> <script src="js/app/myapp.js"></script> <title></title> </head> <body> <h1>Sample Page</h1> </body> </html> |
分割した3つのJSファイルのロード順はmyapp.jsのなかでalpha()やbeta()を使っているので最後にmyapp.jsをロードする必要があるように思えますが、myapp.jsのコードが評価されるのは、$(document).ready()のタイミングですので、それより前にalpha.jsとbeta.jsの評価が完了していれば問題ありません。
まだ、この程度なら問題ないのですが、ロードするJSファイルが増えていくと、依存関係に頭を悩まされることになります。
JSファイルのロードの問題を緩和してくれるのがJavascriptローダーと呼ばれるツールで、その一つがRequireJSです。
3.RequireJSでロード
index.htmlは以下のようになり、<script>は1つで済みます。data-mainという見慣れない属性が出てきましたが、ここで指定したjs/mainは実はjs/main.jsというJSファイルの拡張子を省略したものです。
index.html
1 2 3 4 5 6 7 8 9 10 11 |
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8" /> <script data-main="js/main" src="js/lib/requirejs/require.js"></script> <title></title> </head> <body> <h1>Sample Page</h1> </body> </html> |
js/main.jsは以下のようになっています。alpha.jsとbeta.jsも以下のように編集します。
js/main.js
1 2 3 4 5 6 7 8 9 10 11 12 13 |
requirejs.config({ urlArgs: "bust=" + (new Date()).getTime(), paths: { "jquery": "lib/jquery/jquery" }, shim: { "app/alpha": { deps: ['jquery'] }, "app/beta": { deps: ['jquery'] } }, }); require(["jquery", "app/alpha", "app/beta"], function($) { $(function() { $('body').alpha().beta(); }); }); |
js/app/alpha.js
1 2 3 |
$.fn.alpha = function() { return this.append('<p>Alpha is Go!</p>'); }; |
js/app/beta.js
1 2 3 |
$.fn.beta = function() { return this.append('<p>Beta is Go!</p>'); }; |
js/main.jsについて見ていきます。
まず、11〜15行目は、jquery.jsとapp/alpha.jsとapp/beta.jsがロードできたら2番目の引数function($)…内のコードを評価せよ、という意味です。
1〜9行目がロードの際の設定です。
4〜6行目が大事な箇所で、app/alpha.jsとapp/beta.jsはjqueryに依存します、という宣言です。これがないと、alpha.jsやbeta.jsの”$”が未定義となっておこられます。
依存関係を記述ない場合とした場合のロードの様子を見ると以下のように一目瞭然で、依存関係を記述した場合は、jqueryのロードが完了後、遅れてalpha.jsとbeta.jsがロードされています。
依存関係を記述しない場合
依存関係を記述した場合
2行目はJSファイルのキャッシュを無効にするために、JSファイルを呼び出す際にURLの末尾にパラメータをつけています。リリースの際にはパフォーマンスの観点から忘れずに外しておきましょう。