行きがかり上、JSANモジュールシステムの説明をしておきます。
[追記 dateTime="夕方"]: typoと、本文の趣旨とサンプルコードがずれているところがあったので修正しました。修正の内容は、このエントリーの最後にあります。[/追記]
JSAN(JavaScript Archive Network)は、JavaScriptライブラリ群を集積したアーカイブ・サイトです。そして、JSANがベースとしているモジュール(あるいはパッケージ)システムがJSAN.jsというスクリプトで提供されています。
僕は、モジュールシステムの必要性を強く感じていたので、試しに自作してみたのですが、既に使用されているJSAN.jsがあるので、こっちを使うことに決めました。
この記事と一緒に、次のbrazilさんのエントリーを参照することをお勧めします。
内容:
- こんな事例を考える
- モジュールとモジュールパス
- JSANモジュールシステムを導入しよう
- 利用するときの注意事項
- モジュール側のお約束
- まとめ
●こんな事例を考える
JSANモジュールシステムは、Perlのモジュールシステムの影響を強く受けています。ですから、Perl使いにはお馴染みの仕掛けでしょう。ここでは、Perlの知識を仮定せず、用語/概念も単純化(一部は省略)して説明します。
まずは事例から。Webサーバーに次のようなディレクトリ構造があったとします。
[.]
+---mypage.html
+---myscript.js
+---[lib]
+--Util.js
+---[Search]
+--Fast.js
mypage.htmlでmyscript.jsを使います。つまり:
という記述が、mypage.htmlに必要ですね。
さらに、myscript.jsがSearch/Fast.jsを必要として、Search/Fast.jsがlib/Util.jsを必要としているとしましょう。すべてのJavaScriptプログラムをキチンと揃えるために、次のタグを並べる必要があります。
別にどうってことない? いやいや、".js"ファイル数が増えたり、プログラム(スクリプト)の依存関係が複雑になると、「キチンとscriptタグを並べる」管理作業は悪夢になり得ます。
●モジュールとモジュールパス
他のプログラムから使われることを意図したJavaScriptソースファイルをモジュールと呼びます。わかりやすいように、またJSANの習慣に従い、モジュールのファイル名は大文字からはじめることにします(メカニズム上は、命名は自由だが)。
モジュールの、“ある特定のディレクトリ”を基準とした相対パスをモジュールパスといいます。例えば、先の図の[.]を基準ディレクトリとするなら、Search/Fast.js はモジュールパスです。
では、lib/Util.js もモジュールパスでしょうか? (JSAN.jsの通常の使用法では)違います。./lib/Util.jsファイルのモジュールパスはUitl.jsです。なぜかというと、基準ディレクトリが前もって複数設定されているからです。デフォルトでは、"." と "lib"が基準ディレクトリです。
// JSANソースコード抜粋
JSAN.includePath = ['.', 'lib']; //必要なら変更する
このため、Util.jsは、./Util.js → ./lib/Uitl.js の順で探すことになるので、Util.jsをモジュールパスとしてもOKなのです。ちなみに、Search/Fast.js は、./Search/Fast.js → ./lib/Search/Fast.js と探すので、libの下に置いてもかまいません。
●JSANモジュールシステムを導入しよう
モジュールパスの概念はわかりましたか? モジュールパスから拡張子「.js」を取り除いて、「/」を「.」に置き換えた名前をモジュール名と呼びます。例えば、Search.Fastはモジュール名です。
JSANの習慣では、モジュール名+バージョンがモジュールを特定するグローバル識別子として使われます。配布ファイルの命名は、Search.Fast-0.21.tar.gz またはSearch-Fast-0.21.tar.gz です。
さて、JSANとDebug.Logger(実在のモジュール)を次のように配置したと仮定して話を進めます。
[..]
+-- [jsan]
+---JSAN.js
+---[Debug]
+---Logger.js
+-- [.]
+---mypage.html
+---myscript.js
+---[lib]
+--Util.js
+---[Search]
+--Fast.js
こうすると、mypage.html内の記述は次のようになります。
他のモジュールへの依存関係は、myscript.js内に次のように書きます。必要なモジュールUtilは、Search.Fastからロードされます。
/* myscript.js */
JSAN.use("Search.Fast");
使うモジュールを変更するときも、もはやHTMLファイルを修正する必要はありません。myscript.jsを変更するだけです。例えば:
/* myscript.js */
JSAN.use("Search.Fast");
JSAN.use("Debug.Logger");
アレレッ? Debug.Loggerもちゃんとロードできるの? 大丈夫です。JSAN.jsが存在するディレクトリ(この例では ../jsan/)は自動的にJSAN.includePathに追加されます。つまり、Debug.Loggerのファイルは次の順で検索されます。
- ./Debug/Logger.js
- ./lib/Debug/Logger.js
- ../jsan/Debug/Logger.js
●利用するときの注意事項
ほとんどの言語では、include, import, use, require, consult, loadなどのキーワードにより、他のモジュールの使用/取り込みを指示できます。JSAN.jsは、JavaScriptでもモジュールの取り込み機能を利用できるようにしたものです。
ただし、JSAN.useは宣言ではなくて実行文になります。失敗することもあるので、次のように書くのが無難でしょう。(デバッグ中はthrowではなくて、alertやprintで表示したほうがみやすいね。)
/* myscript.js */
try {
JSAN.use("Search.Fast");
} catch(e) {
throw new Error("This script requires JSAN.js" +
" and modules: Uitl" +
" (" + e.message + ")" );
}
宣言ではないので、ソースの先頭ではなくても任意の場所で(たとえループのなかでも)JSAN.useを使用できます。
JSAN.use以外にJSAN.requireもありますが、これについてはbrazilさんの記事などを参考にしてください。
●モジュール側のお約束
モジュールのファイルは正しい場所(モジュールパス)に置かなくてはなりませんが、書き方に若干のお約束(コンベンション)があります。Search.Fast-0.21(これ、架空のモジュールだけど)なら次のような感じです。
/* Search/Fast.js (Search.Fast-0.21)
*/try {
JSAN.use("Util");
} catch(e) {
throw new Error("Search.Fast requires JSAN to be loaded");
}// 親の名前空間オブジェクトSearchがなければ作る
if (typeof Search == 'undefined') {
Search = {};
}// 当該の名前空間オブジェクトを生成する
Search.Fast = {};/* Search.Fastがクラス(もどき)なら、
Search.Fast = function(mayHaveArgs) { コンストラクタコード }
のようになる。
*/// モジュールのメタ情報:
// それほど律儀に書かなくてもいいが、VERSIONは入れよう。
Search.Fast.NAME = 'Search.Fast';
Search.Fast.VERSION = '0.21';
Search.Fast.EXPORT = ['searchFast'];
Search.Fast.EXPORT_OK = ['searchOptions'];
Search.Fast.EXPORT_TAGS = {
':all': (Search.Fast.EXPORT).concat(Search.Fast.EXPORT_OK),
':common': Search.Fast.EXPORT
};
EXPORT配列に並べた名前(記号)は、JSAN.useが自動的に大域スコープに登録します。したがって、Search.Fast.searchFastは単にsearchFastとしてもアクセスできます。EXPORT_OK配列のなかの名前は要求があれば大域スコープに登録可能です。EXPORT_TAGSは、大域スコープへの登録(export)を便利にする仕掛けです。
これ以上のことは、直接 http://openjsan.org/ にあたってみてください。
●まとめ
- JSANは、JavaScriptライブラリのアーカイブサイトである。
- JSANのモジュールシステムがJSAN.jsとして公開されている。
- モジュールとは、他のスクリプトから使えるJavaScriptソースファイルである。
- モジュールパスとは、モジュールファイルの基準ディレクトリからの相対パスのこと。
- モジュール名は、モジュールパスから拡張子を除き、「/」(パスセパレータ)を「.」に置き換えた名前。
- JSAN.useとJSAN.requireは、複数の基準ディレクトリから、モジュール名で指定したモジュールを探してロードしてくれる。
- モジュールを書く際に、若干のお約束ごとがある。
- JSANモジュールシステムは便利だから、みんな使おう。
[追記 dateTime="夕方"]: 修正した内容:
まず、Farstのrはいらない、Fastですね。
myscript.jsサンプルコードに、JSAN.use("Util") ってのがあったのですが、UtilはSearch.Fastが使うので、myscript.jsではなくて、Search/Fast.js内でJSAN.use("Util")を行うべきです。そのように直しました。[/追記]