Lekumo キャンペーンビルダーと Javascript フレームーク「Closure Tools」

※本記事は、旧 Tech Talk Blog 内の 「Lekumo キャンペーンビルダーと Javascript フレームーク「Closure Tools」 (http://www.sixapart.jp/techtalk/2012/01/lekumo_campain_builder_closure_tools.html) はてなブックマーク - Lekumo キャンペーンビルダーと Javascript フレームーク「Closure Tools」」 で公開されていた記事を移転しました。

どうも、体にこびりついた脂肪と日々戦い続ける、Lekumo キャンペーンビルダー開発担当の間です。

Lekumo キャンペーンビルダーでは、管理画面における Javascript フレームークとして、Closure Tools を採用しています。今回は、この Closure Tools について少しお話をします。

Closure Tools は、

  • Closure Library
  • Closure Compiler
  • Closure Template

の3つと、そして最近リリースされた

  • Closure Stylesheets

から成ります。

開発の基本は、Closure Library にて提供されている部品群を組み合わせてコーディングしていくことになります。開発は、Closure Library さえあれば進めて行くことができます。この為、Closure Library こそが Closure Tools の核と思われそうですが、実は Closure Compiler 無しでは、Closure Library は成り立たないと言っても過言ではありません。

というのも、Closure Library で提供されている部品群はあらゆる用途に対応する為膨大であり、実際には使用しないものまで大量に含まれていたりします。例を挙げると、Lekumo キャンペーンビルダーには「ソーシャルメディア統計」という画面がありますが、この画面では、日付の選択に goog.ui.InputDatePicker という UI を使用しています。

lcb_sms_ui.png

この UI では国際化の為、goog.i18n.DateTimeSymbols というモジュールが必須になるのですが、この goog.i18n.DateTimeSymbols が曲者で、めちゃめちゃサイズがでかいのです。ざっと見ただけでも、

goog.provide('goog.i18n.DateTimeSymbols');
goog.provide('goog.i18n.DateTimeSymbols_ar');
goog.provide('goog.i18n.DateTimeSymbols_bg');
goog.provide('goog.i18n.DateTimeSymbols_bn');
goog.provide('goog.i18n.DateTimeSymbols_ca');
goog.provide('goog.i18n.DateTimeSymbols_cs');
goog.provide('goog.i18n.DateTimeSymbols_da');
goog.provide('goog.i18n.DateTimeSymbols_de');
goog.provide('goog.i18n.DateTimeSymbols_de_AT');
goog.provide('goog.i18n.DateTimeSymbols_de_CH');
goog.provide('goog.i18n.DateTimeSymbols_el');
goog.provide('goog.i18n.DateTimeSymbols_en');
goog.provide('goog.i18n.DateTimeSymbols_en_AU');
goog.provide('goog.i18n.DateTimeSymbols_en_GB');
goog.provide('goog.i18n.DateTimeSymbols_en_IE');
goog.provide('goog.i18n.DateTimeSymbols_en_IN');
goog.provide('goog.i18n.DateTimeSymbols_en_ISO');
goog.provide('goog.i18n.DateTimeSymbols_en_SG');
goog.provide('goog.i18n.DateTimeSymbols_en_US');
goog.provide('goog.i18n.DateTimeSymbols_en_ZA');
goog.provide('goog.i18n.DateTimeSymbols_es');
goog.provide('goog.i18n.DateTimeSymbols_et');
goog.provide('goog.i18n.DateTimeSymbols_eu');
goog.provide('goog.i18n.DateTimeSymbols_fa');
goog.provide('goog.i18n.DateTimeSymbols_fi');
goog.provide('goog.i18n.DateTimeSymbols_fil');
goog.provide('goog.i18n.DateTimeSymbols_fr');
goog.provide('goog.i18n.DateTimeSymbols_fr_CA');
goog.provide('goog.i18n.DateTimeSymbols_gl');
goog.provide('goog.i18n.DateTimeSymbols_gsw');
goog.provide('goog.i18n.DateTimeSymbols_gu');
goog.provide('goog.i18n.DateTimeSymbols_he');
goog.provide('goog.i18n.DateTimeSymbols_hi');
goog.provide('goog.i18n.DateTimeSymbols_hr');
goog.provide('goog.i18n.DateTimeSymbols_hu');
goog.provide('goog.i18n.DateTimeSymbols_id');
goog.provide('goog.i18n.DateTimeSymbols_in');
goog.provide('goog.i18n.DateTimeSymbols_is');
goog.provide('goog.i18n.DateTimeSymbols_it');
goog.provide('goog.i18n.DateTimeSymbols_iw');
goog.provide('goog.i18n.DateTimeSymbols_ja');
goog.provide('goog.i18n.DateTimeSymbols_kn');
goog.provide('goog.i18n.DateTimeSymbols_ko');
goog.provide('goog.i18n.DateTimeSymbols_ln');
goog.provide('goog.i18n.DateTimeSymbols_lt');
goog.provide('goog.i18n.DateTimeSymbols_lv');
goog.provide('goog.i18n.DateTimeSymbols_ml');
goog.provide('goog.i18n.DateTimeSymbols_mo');
goog.provide('goog.i18n.DateTimeSymbols_mr');
goog.provide('goog.i18n.DateTimeSymbols_ms');
goog.provide('goog.i18n.DateTimeSymbols_mt');
goog.provide('goog.i18n.DateTimeSymbols_nl');
goog.provide('goog.i18n.DateTimeSymbols_no');
goog.provide('goog.i18n.DateTimeSymbols_or');
goog.provide('goog.i18n.DateTimeSymbols_pl');
goog.provide('goog.i18n.DateTimeSymbols_pt');
goog.provide('goog.i18n.DateTimeSymbols_pt_BR');
goog.provide('goog.i18n.DateTimeSymbols_pt_PT');
goog.provide('goog.i18n.DateTimeSymbols_ro');
goog.provide('goog.i18n.DateTimeSymbols_ru');
goog.provide('goog.i18n.DateTimeSymbols_sk');
goog.provide('goog.i18n.DateTimeSymbols_sl');
goog.provide('goog.i18n.DateTimeSymbols_sq');
goog.provide('goog.i18n.DateTimeSymbols_sr');
goog.provide('goog.i18n.DateTimeSymbols_sv');
goog.provide('goog.i18n.DateTimeSymbols_ta');
goog.provide('goog.i18n.DateTimeSymbols_te');
goog.provide('goog.i18n.DateTimeSymbols_th');
goog.provide('goog.i18n.DateTimeSymbols_tl');
goog.provide('goog.i18n.DateTimeSymbols_tr');
goog.provide('goog.i18n.DateTimeSymbols_uk');
goog.provide('goog.i18n.DateTimeSymbols_ur');
goog.provide('goog.i18n.DateTimeSymbols_vi');
goog.provide('goog.i18n.DateTimeSymbols_zh');
goog.provide('goog.i18n.DateTimeSymbols_zh_CN');
goog.provide('goog.i18n.DateTimeSymbols_zh_HK');
goog.provide('goog.i18n.DateTimeSymbols_zh_TW');

と、これだけの数の言語がサポートされており、各言語の日付の名称やフォーマットがそれぞれ入っているわけです。この画面で必要となる Library を単純に Combine(結合)すると...

$ ls -l statistics.js
-rw-rw-r-- 1 shazama shazama 2343578 Nov 24 13:54 statistics.js

なんと、2MB を超える巨大なファイルになってしまいます。使いたいのは日本語の部分だけなのに使ってない言語までたんまり読み込まれてしまう為です。

これを解決してくれるのが、Closure Compiler です。Closure Compiler は、単にシンボルの短縮や不要な改行や空白を削除するだけでなく、不要な Function の削除までしてくれます。その為には、ADVANCED_OPTIMIZATIONS というオプション付きで Compile する必要があるのですが、Closure Library と Closure Compiler を組み合わせて使う場合、このオプションは必須だと思った方が良いです。コードの書き方に多少制約が出てきますが、その手間をかけるだけの価値はあります。

試しに、先ほどの JS ファイルを Compile してみます。Compile には、

python closurebuilder.py
--root=/closure/root
sixapart.app.Statistics
-o compiled
--output_file=/compiled/statistics.js
--compiler_jar=compiler.jar
-f "--compilation_level=ADVANCED_OPTIMIZATIONS"
-f "--define=goog.DEBUG=false"

というような呪文を唱えます。結果、

$ ls -l statistics.js
-rw-rw-r-- 1 shazama shazama 119306 Nov 22 16:41 statistics.js

単に Combine しただけでは 2MB だったものが、116KB、約20分の1になってしまいました。ここでは、中でも最も極端な例を挙げましたが、他の画面の Javascript ファイルについても顕著にサイズダウンしています。

ネットを検索してみると、ADVANCED_OPTIMIZATIONS には制約があるので、SIMPLE_OPTIMIZATIONS で Compile されているケースが見られます。しかし、SIMPLE_OPTIMIZATIONS では Closure Library の真価は発揮できません。Closure Library は ADVANCED_OPTIMIZATIONS で無駄をそぎ落とすことを前提に、あのような巨大なサイズになっていると考えられるからです。Closure Library は Closure Compiler を併せて使うならば、是非とも制約をクリアして ADVANCED_OPTIMIZATIONS で Compile するべきです。

ADVANCED_OPTIMIZATIONS におけるコーディングの制約については、以下の記事が参考になります。私も参考にさせて頂きました。

さて、上記で挙げた Closure Tools を構成する要素のうち、Library と Compiler には触れましたが Template と Stylesheets について触れていません。実はこの二つについては、私もまだあまり触っていません。いずれはここで何か書けるくらいには使ってみたいと思います。

Six Apart をフォローしませんか?

次の記事へ

検索評価やソーシャルメディアでシェアされるリンクのURLを統一するのに必要不可欠なcanonical属性とは

前の記事へ

Movable Typeの開発 続編(5年ぶり)