WebOS Goodies

WebOS の未来を模索する、ゲームプログラマあがりの Web 開発者のブログ。

WebOS Goodies へようこそ! WebOS はインターネットの未来形。あらゆる Web サイトが繋がり、共有し、協力して創り上げる、ひとつの巨大な情報システムです。そこでは、あらゆる情報がネットワーク上に蓄積され、我々はいつでも、どこからでも、多彩なデバイスを使ってそれらにアクセスできます。 WebOS Goodies は、さまざまな情報提供やツール開発を通して、そんな世界の実現に少しでも貢献するべく活動していきます。
Subscribe       

デバッグ時の設定 UI を生成する Closure Library の goog.tweak の使い方

よく見たら、今週の話題以外の記事はほぼ 3 ヶ月ぶりですね・・・久々となる本日は、 Closure Library の goog.tweak という機能のご紹介です。

Web アプリを開発する際には、皆さんデバッグ用の機能をいろいろと実装することと思います。一部の機能を変更・無効化したり、内部の状態を上書きしたりとかですね。でも、そうした機能の設定はどこに書いているでしょうか。多くの場合はソースコードの先頭にグローバル変数で書いたりしているのではないでしょうか。

数が少ないうちはそれでも良いのですが、そうした機能は開発を進めるうちに増えていくもの。とくに多人数開発の場合、どの変数がどんな機能を持っているのかが把握できなくなっていきます。また、それらの機能を無効化する方法を統一しておかないと、誤ってデバッグ機能を含んだコードをリリースしてしまうようなことも起こってしまいます。

そんな問題を解消してくれるのが、 Closure Library に実装された TweakUI (goog.tweak) です。デバッグ機能の設定を一括して格納するレジストリを提供し、その 設定 UI も自動生成してくれます。また、 Closure Compiler の機能を利用して、すべてのデバッグ機能をきれいさっぱり削除することも可能です。

Closure Library を使用したあらゆるプロジェクトで活用できる機能だと思いますので、ぜひ参考にしてください!

概要

冒頭であらかた説明してしまいましたが、 goog.tweak はデバッグ機能の設定の保持と、設定 UI の構築をサポートする機能です。実際に goog.tweak で構築した UI を下に貼り付けました(Show Tweaks というリンクをクリックすると表示されます)。

UI で適当に値を変更して「Apply Tweaks」ボタンをクリックすると、ページがリロードされて location.search (URL のクエリーパラメータの部分)にパラメータ値が設定されます。こうすることでページをリロードしても設定値が保持され、ブックマークすればいつでも同じ設定値で動作テストができるというわけです。 UI にも変更した値がきちんと反映されます。

また、「?」をクリックするとパラメータの説明が表示されますし、「コードの実行」ボタンのように JavaScript コードを実行することも可能です。シンプルではありますが、必要な機能がコンパクトにまとめられるようになっています。標準で折りたたまれているので、 position:absolute でページの隅などに配置しておけば、邪魔になりませんね。

基本的な使い方

それでは、基本的な使い方を見ていきましょう。個々のメソッドの説明は後回しにして、まずは基本的な Boolean 値(チェックボックス)の設定項目を例にして流れを追っていきます。

なお、 Closure Library の基礎的なワークフローは既に知っていると仮定しているので、 Closure Library を触ったことがない方は、先にこちらの記事に目を通しておいてください。

HTML

HTML は通常の Closure Library アプリケーションとまったく同じです。設定 UI を表示するための DIV 要素だけを追加しておいてください。

<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"></head>
<body>
  <!-- 設定 UI を表示するための DIV 要素 -->
  <div id="my-tweak-ui"></div>

  <!-- Closure Library の基本 base.js の読み込み -->
  <script src="closure-library/closure/goog/base.js"></script>

  <!-- アプリケーションの deps.js の読み込み -->
  <script src="deps.js"></script>

  <!-- アプリケーションクラスを読み込み、実行 -->
  <script>
    goog.require('tweakuisample.App');
  </script>
</body>
</html>

※ 上記のコードはビルドせずに実行することを前提にしています。

ライブラリを require する

JavaScript ファイルでは、まず goog.tweak と goog.tweak.TweakUi を読み込みます(実際には goog.tweak.TweakUi を読み込むだけで goog.tweak も暗黙的に読み込まれるのですが、念のため)。これにより、必要なメソッド等が利用可能になります。

// このファイルで定義するクラスの宣言
goog.provide('tweakuisample.App');

// goog.tweak と goog.tweak.TweakUi を読み込む
goog.require('goog.tweak');
goog.require('goog.tweak.TweakUi');

設定項目を登録する

goog.tweak に設定項目を登録するには、データ型ごとに用意された goog.tweak.registerXxx() を呼び出します。今回は Boolean 値の項目を登録するので、 registerBoolean() を使います。

goog.tweak.registerBoolean('itemId', '説明テキスト');

第一引数は項目の ID で、値を取得する際にこの名前を指定するほか、 URL に追加するクエリーパラメータ名などにも使われます(オプション引数で変更可能)。第二引数は項目の説明(「?」をクリクされた時に表示されるもの)です。これ以外にも省略可能な引数がありますが、それについては後述します。

注意すべき点は、これらの登録メソッドはグローバルスコープで実行しなければいけないという点です。関数内で実行してしまうと、後々の Closure Compiler との連携等で不具合が生じます。実は微妙に例外もあるのですが、この記事では省略しています。すいません。

UI を構築する

必要な項目を追加したら、 UI を構築します。 goog.tweak.TweakUi.createCollapsible() を呼び出せば UI の DOM オブジェクトが返るので、それをドキュメントに挿入するだけです。

var tweakEl = goog.tweak.TweakUi.createCollapsible();
if(tweakEl) {
  goog.dom.getElement('my-tweak-ui').appendChild(tweakEl);
}

createCollapsible() の返り値をチェックしているのは、後に Closure Compiler を利用して goog.tweak 周りのコードを削除するためです。コンパイル時に tweak の削除を指示すると、 createCollapsible() が常に null を返すものとして処理され、上記の if 文の中がバッサリ削除されます。

設定値の取得

コード中で設定値を取得する場合は、これまたデータ型ごとに用意された goog.tweak.getXxx() メソッドを使います。 Boolean 値の取得なら goog.tweak.getBoolean() です。引数に registerBoolean() の第一引数と同じ文字列を指定してください。

if(goog.tweak.getBoolean('itemId')) {
  // ...
}

この getXxx() の呼び出しも Closure Compiler によって削除されることを意識しておいてください。 tweak の削除が行われると、 getXxx() はその項目のデフォルト値で置き換えられます。コンパイラによる最適化の恩恵を最大限に引き出すためには、できるだけ設定値を変数に保持したりせず、必要なときに毎回 getXxx() を呼び出すべきです。

メソッドの詳細

すでに goog.tweak の使い方が概ね把握できたかと思いますが、細かい点でいくつか疑問もあるでしょう。例えば UI に表示するラベルに日本語を使いたい時はどうするかや、冒頭のサンプルにあったドロップダウンはどうやって表示するか、などですね。もちろんそうしたカスタマイズも可能になっているので、それらの詳細を載せておきます。

設定項目の追加

設定項目を追加するメソッドは、前述のとおりデータ型ごとに用意されています。具体的には、以下の 3 つです。

  • goog.tweak.registerString(id, description, opt_defaultValue, opt_configParams)
  • goog.tweak.registerNumber(id, description, opt_defaultValue, opt_configParams)
  • goog.tweak.registerBoolean(id, description, opt_defaultValue, opt_configParams)

どのメソッドがどのデータ型に対応するかは自明ですよね。そして引数の id, description はすでに説明済みなので、残りの省略可能な引数を見ていきましょう。

第三引数の opt_defaultValue は名前のとおり、デフォルト値を設定するものです。ここで指定した値は URL パラメータがないときのデフォルト値として使われるほか、 Closure Compiler によって tweak が削除された際のその項目の値として使用されます。従って、指定する値はリテラルでなければなりません。省略時は、空文字列、 0 、 false のいずれかになります。

第四引数の opt_configParams には、以下のフィールドを持つオブジェクトが指定できます。

フィールドデフォルト指定する値
label第一引数の値UI のラベルとして表示される文字列
paramName第一引数の値設定値を URL のクエリーパラメータに書き出す際のパラメータ名
restartRequiredtrue設定値が変更された際にページの再ロードが必要かどうか
token第一引数の値グループ化された Boolean 値をクエリーパラメータにエンコードする際の文字列
validValuesなし取り得る値を並べた配列
callbackなし設定値が変更された際に呼ばれるコールバック関数

例えば、 UI に表示される項目名を日本語にしたければ、 id に日本語を直接指定せず、 opt_configParams の label で指定してください。

goog.tweak.registerBoolean('itemId', '説明', false, { label: 'アイテム名' });

validValues を指定すると、 UI がドロップダウンによる選択式になります。

goog.tweak.registerString(
  'select', '選択式の項目', '', { validValues:['', '選択肢1', '選択肢2'] });

token については次を参照してください。その他のフィールドの例は省略しますが、まあ説明のとおりの機能ですので、試してみてください。

グループ化された Boolean 値の追加

冒頭のサンプルの一番下には「BooleanGroup」というリンクがあり、それをクリックするとボックスに囲まれたチェックボックスが現れます。このようなグループ化された Boolean 値を実現するには、 registerBoolean() の呼び出しを beginBooleanGroup(), endBooleanGroup() で囲います。

goog.tweak.beginBooleanGroup('fruits', 'グループ化', { label: '好きな果物' });
goog.tweak.registerBoolean('apple', 'りんご', false, { token: 'a', label: 'りんご' });
goog.tweak.registerBoolean('orange', 'オレンジ', false, { token: 'o', label: 'オレンジ' });
goog.tweak.registerBoolean('grape', 'ぶどう', false, { token: 'g', label: 'ぶどう' });
goog.tweak.endBooleanGroup();

こうすると、冒頭サンプルの「BooleanGroup」と同様にグループ化されたチェックボックスが表示できます。この場合、例えば「りんご」と「オレンジ」をチェックすると、クエリーパラメータはこうなります。

fruits=a,o

パラメータ名が beginBooleanGroup() の id で、値として registerBoolean() の token で指定した文字列がコンマ区切りで並ぶ、という仕組みです(token を省略すると、代わりにそれぞれの id が使われます)。多数のチェックボックスを配置するときは、この機能を使うことで URL を短くできます。

JavaScript を実行するボタンの追加

goog.tweak.registerButton() を使うと、 JavaScript を実行するだけのボタンも追加できます。

goog.tweak.registerButton(
  'showurl', 'ページのURLを表示します',
  function() { alert(location.href); },
  'URLの表示');

第一引数、第二引数は registerBoolean() 等と同じです。第三引数はボタンがクリックされた際に実行する関数、第四引数はボタンに表示するラベル(省略すると第一引数が使われます)です。

デフォルト値の上書き

goog.tweak.overrideDefaultValue() を使用すると、特定の項目のデフォルト値を上書きできます。例えば以下のようにすると、 itemId のデフォルト値を上書きします。

goog.tweak.overrideDefaultValue('itemId', True);

ユースケースとしては、独立した .js ファイルに上記の呼び出しを並べることで、個々の開発者が設定項目のデフォルト値を上書きできるようにする、というようなことが考えられているようです。

なお、 overrideDefaultValue() の呼び出しは、対応する registerXxx() よりも前になければいけないので、注意してください。

値の取得

値の取得も登録と同様にデータ型ごとの 3 つのメソッドが用意されています。

  • goog.tweak.getString(id)
  • goog.tweak.getNumber(id)
  • goog.tweak.getBoolean(id)

いずれも引数に項目の id を指定すれば、値が取得できます。

UI の構築

既に createCollapsible() を使った UI の構築方法を紹介していますが、実は UI の構築メソッドには以下の 2 つがあります。

  • goog.tweak.TweakUi.create(opt_domHelper)
  • goog.tweak.TweakUi.createCollapsible(opt_domHelper)

前者は UI の折りたたみ機能がない、単にフォーム要素が並んでいるだけの DOM を構築します。アプリケーション独自のパネル等に設定 UI を組み込む際などに便利でしょう。

また、両メソッドの引数には goog.dom.DomHelper のインスタンスが指定できます。通常は省略で大丈夫ですが、 iframe や別ウィンドウに UI を表示する際には、適切な DomHelper を指定してください。

Closure Compiler による tweak の削除

めでたくアプリケーションが完成し、リリースの段階になると、当然ながらすべてのデバッグ機能は削除する必要があるでしょう。 goog.tweak では、 Closure Compiler による最適化でそれを自動的に実行します。それどころか、すべての設定値を定数として扱い、不要なデバッグコードを可能な限り削除してくれます。これが goog.tweak の最大の利点といってもいいでしょう。

しかし、実はひとつ問題があります。この tweak の削除機能、なんとコマンドラインの Closure Compiler からは利用できないのです。 Closure Compiler のソースでは完全に実装されているのですが、なぜかその機能を有効にするためのオプションがないのです。

Closure Compiler のソースを変更するという手もあるのですが、なにかほかに良い手はないかなーと探したところ、どうやら Plovr という Closure Library 向けの支援ツールが使えることがわかったので、その方法をご紹介します。

Plovr とは

Plovr は、 Closure Compiler と Closure Template を統合した開発用 Web サーバーで、リクエストに応じてリアルタイムで Closure Compiler によるビルドを行うほか、オフラインで closurebuilder.py + Closure Compiler の代わりビルドツールとしても使えます。

http://plovr.com/

ちなみに作者はオライリーの Closure: The Definitive Guide の著者でもある Michael Bolin 氏です。さすがですなー。

plovr にはほかにも標準の Closure Compiler にはない機能がいろいろあり、 Closure Library による開発にはとても便利なツールです。ここでは tweak の削除に絞って使い方を紹介しますが、ぜひ他の機能も調べてみてください。

インストール

Plovr のビルド済みバイナリが Google Project Hosting で配布されているので、それを使うのが手軽です。

http://code.google.com/p/plovr/downloads/list

.jar ファイルそのものがダウンロードできるので、それを適当な場所にコピーすればインストールは終わりです。

設定ファイルの作成

Plovr でビルドするには、まず JSON 形式の設定ファイルを書かなくてはなりません。内容は概ね以下でいけるはず。

{
  // プロジェクトのID(適当な文字列でOK)
  "id":      "tweakuisample",

  // ビルドする.jsファイルのディレクトリ
  "paths":   "js",

  // ビルドの起点となる.jsファイル
  "inputs":  "js/tweakuisample.js",

  // コンパイルモードの指定
  "mode":    "ADVANCED",

  // Closure Libraryのgoogディレクトリの位置
  "closure-library": "closure-library/closure/goog",

  // tweakの削除を指定
  "experimental-compiler-options": {
    "tweakProcessing": "STRIP"
  }
}

それぞれの項目の意味はコメントのとおりなので、プロジェクトに合わせて変更してください。さらに詳細な指定が必要な場合は、ドキュメントを参照してください。

ビルド

設定ファイルを書いたら、あとは以下のコマンドを実行するだけでビルドができます。

java -jar plovr.jar build config.js > built.js

built.js の内容を覗けば、 tweak のコードがすべて削除されているのがわかるはずです。

以上、本日は Closure Library のデバッグ設定 UI 構築機能をご紹介しました。こういう渋い機能が多数実装されているのが Closure Library の利点ですね。ほかにもいろいろあるので、折をみて取り上げていきたいと思います。

関連記事

この記事にコメントする

Recommendations
Books
「Closure Library」の入門書です。
詳しくはこちらの記事をどうぞ!
Categories
Recent Articles