Dojoツールキットにはソース・コードをビルドする機能が備わっており、Dojoの最も優れた機能の一つとも言われています。中規模以上のDojoベースのアプリケーション開発では欠かすことのできない必須の機能と言えます。3部構成の前編では、JavaScriptコードをビルドするとはどういう意味で、どのようなメリットがあるのかを説明し、さらに具体的なビルド・システムの使い方を紹介します。
はじめに
DojoベースのWebアプリケーション開発は、ローカル・ファイルをブラウザで開く形で作業を進めることができます。サーバーが不要で手軽なため、そのような手法をとることが多いと思います。やがて、アプリケーションがある程度完成してきたら、テスト環境あるいは本番環境のサーバーへの移行をする必要が出てきます。この時点で検討していただきたいのがアプリケーションのソース・コードの「ビルド」です。ビルドはソース・コードを変換してリリース版として適したモジュールを生成するプロセスです。 Dojoツールキットにはソース・コードをビルドする機能が備わっており、Dojoの最も優れた機能の一つとも言われています。中規模以上のDojoベースのアプリケーション開発では欠かすことのできない必須の機能と言えます。
3部構成の本稿では、まず(1)でJavaScriptコードをビルドするとはどういう意味で、どのようなメリットがあるのかを説明し、さらに具体的なビルド・システムの使い方を紹介します。続編の(2)ではビルドに関連したより高度なパフォーマンス・チューニングのテクニックを紹介します。さらに、(3)ではパフォーマンス・チューニング手段としても使えるXDローダーを紹介したいと思います。
ビルドとは
言うまでもありませんが、JavaScriptはインタープリター型の言語です。C言語やJavaのように、実行するためにソース・コードをコンパイルする必要はありません。従って、Dojoベースのアプリケーションも基本的にはソース・コードのままでも動作します。では、Dojoのビルド・システムが何をしてくれるかと言えば、簡単に言えばソース・コードの圧縮です。そのため、Dojoのビルド・システムはコンプレッサー(compressor)と呼ばれることもあります(コンパイラと呼ばれることもあります)。JavaScriptやCSSのコードを解析し、コメントや省略可能なスペースや改行を取り除いたり、ローカル変数名などの識別子を短くしたりすることにより、コードの意味を変えずにバイト数を減らす変換を施します。また、コード取得のリクエスト回数を減らすために、複数ファイルを一つにまとめることも行います。このように、完成したアプリケーションを最適なパフォーマンスで運用するための「リリース版」を作成するのがビルドの主な目的です。
ビルドのメリット
以下、ビルドの主なメリットについて説明します。
ソース・コードのサイズが小さくなる
コードの実行に不要なコメントやホワイトスペースを取り除き、長い変数名も短くしてくれるので、コード・サイズが大幅に縮小されます。コメント等の量により圧縮率は変わりますが、元のサイズのおよそ1/2から1/3程度に圧縮されることを期待できます。コード・サイズの縮小は、コードのダウンロード時間の短縮につながります。また、それを受け取るブラウザにとってもより少ないメモリで効率よく構文解析することができます。結果としてパフォーマンスの向上に寄与します。特に、モバイル・デバイスのように帯域幅、受信サイズ、キャッシュ容量などに制約がある場合は重要な要素になります。
ソース・コードのファイル数が少なくなり、リクエスト回数が減る
サーバーへの要求と応答(ラウンド・トリップ)はコストの高い処理であり、それを多数繰り返すことはパフォーマンスの低下につながります。ビルドを行うことにより、例え100個のJavaScriptファイルがあっても、設定により一つまたは数個のJavaScriptファイルにまとめることができるため、リクエスト回数を大幅に減らすことができます。
CSSファイルに関しても、@importによる外部ファイル参照があればそれをインライン展開することでファイル数を減らしますし、もちろんコメントやホワイトスペースの削除も行います。
また、ウィジェットの実装で使われるテンプレート・ファイルに関しては、ファイルの内容が文字列としてウィジェットのソース・コードに埋め込まれるので、テンプレートを取得するためのリクエストが発生しなくなります。
ソース・コードを読みにくくし(難読化)、解析しにくくする
コメントやホワイトスペースの削除と変数名などの識別子の短縮は、下のコードの例のように、結果としてソース・コードの難読化をもたらします。暗号化しているわけではありませんが、リバース・エンジニアリングなどコードの解析を困難にする効果があります。
for(var i=0,p;obj&&(p=_1c[i]);i++){if(i==0&&this._scopeMap[p]){p=this._scopeMap[p];}obj=(p in obj?obj[p]:(_1d?obj[p]={}:undefined));}return obj;};dojo.setObject=function(_22,_23,_24){var _25=_22.split("."),p=_25.pop(),obj=d._getProp(_25,true,_24);return obj&&p?(obj[p]=_23):undefined;};dojo.getObject=function(_28,_29,_2a){return d._getProp(_28.split("."),_29,_2a);};dojo.exists=function(_2b,obj){return !!d.getObject(_2b,false,obj);};dojo["eval"]=function(_2d){return d.global.eval?d.global.eval(_2d):eval(_2d);};d.deprecated=d.experimental=function(){};})();(function(){var d=dojo;
準備
Dojoをビルドするにはビルド・ツールを使用します。ビルド・ツールはdojo, dijit, dojoxディレクトリと並ぶutilディレクトリに格納されていますが、Dojoの標準のリリース版パッケージ(dojo-release-1.x.x.zip等)にはutilディレクトリが含まれていません。ビルド・ツールを利用するには、ソース・コード版パッケージ(dojo-release-1.x.x-src.zip等)をダウンロードしてください。
また、ビルド・ツールはRhinoと呼ばれるJavaで実装されたJavaScriptインタプリタを利用するため、Javaの実行環境(J2SE 1.4.2以上)が必要です。
ビルドの実行
まず、ビルドを実行するコマンドが存在するutil/buildscriptsディレクトリに移動します。
次に、ビルド・コマンドを実行します。
ここでは、まだオプションを何も与えていないので、コマンドを実行するとヘルプ・テキストが表示されます。
ビルド・コマンドのファイルの内容を見ると分かりますが、次のようなたった1行のJavaの呼び出しでビルドが実行されます。従って、MakefileやAntスクリプトなど他のビルド環境から直接このJava呼び出しを行うことも容易にできます。
java -classpath ../shrinksafe/js.jar:../shrinksafe/shrinksafe.jar
org.mozilla.javascript.tools.shell.Main build.js "$@"
典型的なビルド・コマンドの実行例を示します。この例ではプロファイル・ファイルとしてutil/buildscripts/profiles/standard.profile.js(※1)を使用してビルドを行います。
> build profile=standard action=release
ビルド結果はdojoやdijitなどと同じフォルダのreleaseという名前のフォルダに生成されます。
release/dojo/dojo/build.txtを見ると、どのレイヤー(後述)にどのようなモジュールが取り込まれたか確認できます。
圧縮された各レイヤー・ファイル*.jsに対し、圧縮されていない*.js.uncompressed.jsファイルも同時に生成されます。ビルドされた状態でのデバッグを行いたい場合に使用します。
※1
Dojoの標準のリリース版パッケージ(dojo-release-1.x.x.zip等)はこのstandardプロファイルを使ってビルドされています。
ビルド・コマンドのオプション
ビルド・コマンドで利用できるオプションを表1に示します(マルチ・バージョンなど一部の高度なオプションは除く)。
表1. ビルド・コマンドのオプション
|
オプション |
説明 |
|
cssOptimize |
CSSファイルの最適化の方法を指定します。commentsを指定すると、CSSファイルのコメントと改行が取り除かれ、@import文で参照している外部CSSファイルの内容が展開されます。comments.keepLinesを指定すると、コメントの削除と@importの展開は行われますが、改行は保持されます。 |
|
cssImportIgnore |
cssOptimize=commentsオプションを使うとすべての@importが展開されますが、このオプションを使うことにより特定のファイルだけ展開されないようにできます。展開されたくないファイル名をコンマ区切りでこのオプションの値として与えます。ファイル名は、@import文の呼び出しに使われている文字列にマッチします。 |
|
releaseDir |
ビルド結果が格納されるトップ・レベルのリリース・ディレクトリのパスを指定します。このディレクトリの中に、releaseNameオプションで指定されるディレクトリが作られます。デフォルト値は../../release/です。 |
|
releaseName |
リリース名を指定します。releaseDirオプションで指定されるディレクトリの中に、このオプションで指定した名前のディレクトリが作られます。デフォルト値はdojoです。 |
|
localeList |
i18nバンドルをフラット化する対象となるロケールをコンマ区切りで指定します。 |
|
copyTests |
テスト・ファイルをコピーするか否かを指定します。デフォルト値はtrueです。 |
|
action |
ビルドのアクションを指定します。action=clean,releaseのようにコンマ区切りで複数のアクションを指定できます。指定可能なアクションはcleanおよびreleaseです。 |
|
symbol |
無名関数であるDojoのメソッドにグローバルな関数シンボルを与えることにより、デバッガでシンボルが確認できるようにします(特にDojoのメソッド名がうまく表示できないIEのデバッガでは効果があります)。オプションの値として、longまたはshortを指定できます。shortを指定すると、ソース・コードには短いシンボル名が与えられ、長い名前との対応関係がsymboltables.txtというファイルに記録されます。 |
|
internStrings |
ウィジェットの外部テンプレート・ファイルをウィジェット内に展開して埋め込むか否かを指定します。デフォルト値はtrueです。 |
|
mini |
tests、demos、dijit/bench、未完成のthemes、ウィジェット本体に埋め込み済みのテンプレート・ファイルなどをビルド結果から削除します。copyTestsオプションの設定を上書きします。デフォルト値はfalseです。 |
|
optimize |
モジュール・ファイル(各モジュールごとのJavaScriptファイル)の最適化の方法を指定します。commentsを指定すると、コメントが取り除かれます。shrinksafeを指定すると、Shrinksafeと呼ばれるJavaScript圧縮ツールを使って最適化され、改行も削除されます。shrinksafe.keepLinesを指定すると、Shrinksafeを使って最適化されますが、改行は保持されます。packerを指定すると、Dean Edwards氏のPackerと呼ばれるJavaScript圧縮ツールを使って最適化されます。デフォルトでは最適化されません。 |
|
layerOptimize |
レイヤー・ファイル(複数のモジュールを一つに結合したJavaScriptファイル。dojo.jsなど)の最適化の方法を指定します。commentsを指定すると、コメントが取り除かれます。shrinksafeを指定すると、Shrinksafeと呼ばれるJavaScript圧縮ツールを使って最適化され、改行も削除されます。shrinksafe.keepLinesを指定すると、Shrinksafeを使って最適化されますが、改行は保持されます。packerを指定すると、Dean Edwards氏のPackerと呼ばれるJavaScript圧縮ツールを使って最適化されます。デフォルト値はshrinksafeです。 |
|
log |
ビルド・コマンドが表示するログの詳細レベルを指定します。0から3までの整数を指定できます。デフォルト値は0です。
|
0 |
TRACE |
|
1 |
INFO |
|
2 |
WARN |
|
3 |
ERROR |
|
|
profile |
ビルドに使用するプロファイル名を指定します。profilesディレクトリに存在するプロファイル・ファイル名の先頭部分を指定します。例えば、プロファイル・ファイルとしてbase.profile.jsを使用する場合は、profile=baseと指定します。デフォルト値はbaseです。 |
|
profileFile |
プロファイル・ファイルのパスを指定します。プロファイル・ファイルがprofilesディレクトリの外に存在する場合に使用します。このオプションを使用する場合は、profileオプションは指定しません。 |
|
expandProvide |
dojo.provideの呼び出しを展開し、より高速なコードに置き換えます。ただし、より高速な実行と引き換えに、ファイル・サイズは若干増加します。プロファイリングにより、dojo.provideの呼び出しに無視できないほどの時間がかかっていることが判明した場合にのみ使用してください。dojo.provideは名前を引くためにややコストの高いdojo.getObjectを呼び出します。このオプションを使用すると、例えば、dojo.provide("foo.bar")という文が、それと等価な効果を持つ次のようなコードに置き換えられ、dojo.getObjectの呼び出しを回避します。
if(typeof foo=="undefined"){foo={};};foo.bar=foo.bar||{};
- 「Dojo道場」~実用アプリ構築のためのベストプラクティス連載記事一覧
-
もっと読む
- この記事の著者
-
神山 淑朗(カミヤマ ヨシロウ)
日本アイ・ビー・エム株式会社 ソフトウェア開発研究所に勤務。現在は主にdojoベースのwebアプリケーションの研究開発に従事。
※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です
この著者の最近の執筆記事
CodeZine(コードジン)
codezine.jp
https://codezine.jp/static/common/images/czlogo4fb_ogp.png
https://codezine.jp/article/detail/5693
2012/01/30 11:49
CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内
- ・全ての過去記事が閲覧できます
- ・会員限定メルマガを受信できます
メールバックナンバー
|