Google Closure Libraryの依存関係解決ツールは非常に便利。
Closure Libraryのインストール
ファイルをダウンロードしたら解凍しアプリケーションのpublicディレクトリに設置する。ここでいうpublicディレクトリに設置するというのは
application
`-- public
`-- javascripts
|-- closure-library
| |-- closure
| | |-- bin
| | | `-- build
| | | |-- closurebuilder.py
| | | `-- depswriter.py
| | `-- goog
| | `-- base.js
| `-- third_party
`-- myapp
|-- base.js
`-- main.js
のようになっているとしてpublicディレクトリ以下のファイル間のファイルシステム上での相対位置とURIとしての相対位置が同じになることを意味する。
依存関係の記述
Railsのassetsパイプラインにはファイル間の依存関係を書く事ができるが、Closure Libraryではファイル単位ではなくObject単位での依存関係を記述することができる。
使うのはgoog.provide
とgoog.require
。これら自体はclosure-library/closure/goog/base.js
に定義されている。一つのファイルが提供・要求するオブジェクトの数に制限は無い。
// base.js
goog.provide('app') // 提供するオブジェクトの宣言
var app = {}
app.version = 1
// main.js
goog.provide('app.run') // 提供するオブジェクトの宣言
goog.require('app') // 必要とするオブジェクトの宣言
var app;
app = app || {};
app.run = function() {
alert(app.version) // => 1
}
依存ファイルの生成
goog.provide
とgoog.require
から依存関係を抽出する。これにはdepswriter.pyというスクリプトを使う。通常この結果をdeps.jsという名前で保存する。(Closure Library内部の依存関係はclocure-libaray/closure/goog/deps.jsに保存されており、goog/base.jsが読み込まれると自動でこちらも読み込まれるようになっている。)
% python public/javascripts/closure-library/closure/bin/build/depswriter.py \
--root_with_prefix='public/javascripts/myapp ../../../myapp' \
--output_file=public/javascripts/myapp/deps.js
root_with_prefix
オプションで自分のJSコードの絶対パスとgoog/base.jsからの相対パスを指定する。間にスペースが一つ入っているのに注意。この指定されたディレクトリ以下のファイルが全て調べられoutput_file
ディレクトリに結果が保存される。
今回の場合deps.jsは次のようになる
// This file was autogenerated by public/javascripts/closure/bin/build/depswriter.py.
// Please do not edit.
goog.addDependency('../../../myapp/base.js', ['app'], []);
goog.addDependency('../../../myapp/main.js', ['app.run'], ['app']);
ブラウザで実行する(開発時)
goog/base.jsと先ほど作ったdeps.jsと起点となるファイルを読み込む
<!DOCTYPE html>
<html>
<head>
<title>myapp</title>
</head>
<body>
<script src="javascripts/closure-library/closure/goog/base.js"></script>
<script src="javascripts/myapp/deps.js"></script>
<script src="javascripts/myapp/main.js"></script>
<script>
window.onload = app.run
</script>
</body>
</html>
この場合main.jsが読み込まれるとClosure Libraryが自動的に依存しているbase.jsを読み込む。
ソースコードを一つにまとめる
本番環境ではソースコードを一つにまとめたい。この用途にはclosurebuilder.pyを使う
% python public/javascripts/closure-library/closure/bin/build/closurebuilder.py \
--root=public/javascripts \
--namespace=app.run \
--output_file=public/javascripts/myapp.js \
--output_mode=script
namespace
オプションで起点となるオブジェクトを指定する。今回ならmain.jsに提供しているので、このファイルを起点にして依存するファイルをまとめていく。
myapp.jsというJSファイルが生成されているので、これをブラウザで読みこめばいい。下記はファイルの読み込みが一回で済む分だけ、前の例より効率がいい。
<!DOCTYPE html>
<html>
<head>
<title>myapp</title>
</head>
<body>
<script src="javascripts/myapp.js"></script>
<script>
window.onload = app.run
</script>
</body>
</html>
ソースコードを圧縮する
JSファイルを圧縮するツールはいくつかあるが、ここではGoogle Closure Compilerを使う。ダウンロードして解凍すると中にcompiler.jarがあるので適当な場所に設置する。上で使ったclosurebuilder.pyにはオプションでコンパイル時にClosure Compilerで圧縮するオプションがある。
% python public/javascripts/closure-library/closure/bin/build/closurebuilder.py \
--root=public/javascripts \
--namespace=app.run \
--output_file=public/javascripts/myapp.js \
--output_mode=compiled \
--compiler_jar=path/to/compiler.jar \
--compiler_flags='--compilation_level=ADVANCED_OPTIMIZATIONS'
compiler_jar
オプションで先程のcompiler.jarを指定する。compiler_flags
は圧縮レベルでWHITESPACE_ONLY
SIMPLE_OPTIMIZATIONS
ADVANCED_OPTIMIZATIONS
の三つの中から選ぶ。