RequireJSにはこんな機能もあった
この記事はJavaScript - Client Side - Advent Calendar 2013 17日目の記事です。
JavaScriptでモジュール管理を実現できるRequireJSですが、どんくらい使われてるのでしょうかねー?初めて触ったときは、すげー!って思ったのを覚えています。
でも、試しに使ったことはあったものの、最近になって初めてちゃんと使いました。周りでもあんまり使ってる人見ないような・・・、普段はバックエンドの仕事をしているせいかな・・・。
それで、RequireJSのドキュメントを読んでたわけですが、こんな機能もあったのかぁ、ということがあったので書きます。
RequireJSがどんなものかはWeb上に情報がたくさんあるので割愛します。
使用したRequireJSのバージョンは、2.1.9です。
requireメソッドを使って、Consoleデバッグ
最初はrequireメソッドを使うとConsoleデバッグできますよ、というお話。
公式サイトの説明はこちら -> http://requirejs.org/docs/api.html#modulenotes-console
さて、RequireJSでは、別のモジュールに依存しているモジュールを書く場合は以下のように書く。
define(['mod1', 'mod2', 'mod3'], function(mod1, mod2, mod3){ // ・・・ });
define()
の第1引数に依存するモジュール達を記述しておくと、第2引数の関数の引数にそのモジュールが達が渡される。モジュールの記述順と引数の順番を揃える必要があるので、依存するモジュールが増えると管理しずらくなる。
そこで、require()
メソッドを使うと以下のように書くことができる。
define(['mod1', 'mod2', 'mod3'], function(){ var mod1 = require('mod1'), mod2 = require('mod2'), mod3 = require('mod3'); // ・・・ });
これで、引数の順番とか気にする必要がなくなった。
ここからが本題で、このrequire()
メソッドをブラウザのJavaScriptコンソールで使うことで、モジュールを取得できる。
> var mod1 = require('mod1'); > mod1.hoge();
こんな感じで、モジュールをコンソールから自由に使えるようになるので、デバッグがしやすくなる。これは便利そう!
JSONP
お次は、JSONPで取得したJSONをRequireJSのモジュールとして扱う機能。
公式サイトの説明はこちら -> http://requirejs.org/docs/api.html#jsonp
以下のように依存するモジュール名ではなく、JSONPに対応したAPIのURIを指定しコールバック関数をdefineとしておくだけ。
define(['http://localhost/api.json?callback=define'], function(data){ // ・・・ });
これだけでできちゃうんだけど、JSONPを使うってことは外部サービスに依存することになると思うのでエラー時の処理がより大事になる。
APIのレスポンスコードが200なんだけどメッセージがJSON形式でない場合、上の例だとdata
はundefined
になる。
APIのレスポンスコードが404や500の場合、RequireJSの例外が発生する。このエラーをハンドリングしたい場合はdefineの第3引数としてエラーハンドリング用の関数を定義する。
define(['http://localhost/api.json?callback=define'], function(data){ // ・・・ }, function(err){ console.log(err); // {requireType: "scripterror", requireModules: ["http://localhost/api.json?callback=define"], originalError: Event} });
200でメッセージがJSON形式でない場合もエラーハンドラで処理したい場合は、configでenforceDefine
をtrue
に設定すれば例外を発生させることができる。
require.config({ enforceDefine: true }); define(['http://localhost/api.json?callback=define'], function(data){ // ・・・ }, function(err){ console.log(err); // {requireType: "nodefine", requireModules: ["http://localhost/api.json?callback=define"]} });
こんな感じでJSONPで取得したJSONをモジュールとして扱うことができることが分かった。
プラグインを使ってi18n対応
RequireJSのプラグインを使って国際化対応ができる。
公式サイトの説明はこちら -> http://requirejs.org/docs/api.html#i18n
プラグインは以下のページからダウンロードできる。
http://requirejs.org/docs/download.html#i18n
まず、ダウンロードしたi18n.jsをdata-mainに指定するjsファイルと同じディレクトリへ配置。ここでは、$PROJECT_ROOT/public/jsに置くとする。
次にnlsというディレクトリを作成し、その中に国際化対応したい文字列を定義したモジュールを作成する。root
というプロパティに定義したい文字列を定義していく。
例えば、色の名前を定義したcolorsモジュールは以下のような感じ。
// $PROJECT_ROOT/public/js/nls/colors.js define({ root: { red: "red", blue: "blue", green: "green" } });
今度は、colorsモジュールを使う側のコード。colorsモジュールを指定するときにプレフィックスとして"i18n!"をつける。そうすると、i18nプラグインを利用してcolorsモジュールを読み込むことができる。
// $PROJECT_ROOT/public/js/main.js require(['i18n!nls/colors'], function(data){ console.log(data); // {red: "red", blue: "blue", green: "green"} });
これでdata
に、colorsモジュールのrootプロパティに定義したオブジェクトがセットされる(i18n!を付かなかった場合は通常通りdefineに指定したオブジェクトがセットされる)。
じゃあ、colorsモジュールを国際化してみる。日本語版をcolorsモジュールを作ってみる。nls/colors.jsに、ja: true
を追加。
// $PROJECT_ROOT/public/js/nls/colors.js define({ root: { red: "red", blue: "blue", green: "green" }, ja: true });
日本語の色名をnls/ja/colors.jsに定義する。
// $PROJECT_ROOT/public/js/nls/ja/colors.js define({ red: "赤", blue: "青", green: "緑" });
ブラウザの言語設定が日本語にしておくと、以下のようにdata
には、nls/colors.jsではなく、jaディレクトリに作ったnls/ja/colors.jsで定義したオブジェクトがセットされる。
require(['i18n!nls/colors'], function(data){ console.log(data); // {red: "赤", blue: "青", green: "緑"} });
こんな感じで国際化対応ができた。
ただ、r.jsでファイルを結合した場合、うまく動かない・・・。
nls/colors.jsは結合後のjsファイルに含まれるが、nls/ja/colors.jsは含まれないみたい。そのため、nls/ja/colors.jsが必要な時は、結合していない時と同じようにRequireJSにより非同期ロードが行われる。この時のリクエストURLが、/public/js/nls/ja/colors.jsではなく、/nls/ja/colors.jsになってしまい、nls/ja/colors.jsが404エラーになり正常に動かない。
以下のようにpathsの設定を使えば対応できるけど、言語毎に設定するのは面倒だなー。何かいい方法があるのかも。
require.config({ paths: { "nls/ja": "public/js/nls/ja" } }); require(['i18n!nls/colors'], function(data){ console.log(data); // {red: "赤", blue: "青", green: "緑"} });
サーバーサイドからデータ取ってくる場合はサーバーサイドで国際化対応すればいいと思うけど、クライアントサイドのみで動かしているアプリケーションを国際化対応したい場合は便利かもなー。
おしまい
コンソールデバッグ、JSONP、i18nの3つを使ってみました。
プラグインを見ると色々ありそうでしたけど、RequireJSでやる必要ないんじゃない、とか利用シーンが思いつかないものが多かったです。
とはいえ、JavaScriptでモジュール管理できるのはうれしいので、RequireJSを使い込んでみたいなぁと思っている次第でございます。