ocamljsが生成したソースをclosure compilerで圧縮する

ocamljsが生成するJavaScriptのソースは大きくなりがちなので、minifier等でできるかぎり小さくできることが望ましい。その点で closure compiler はかなり良い。 スペースを削除するだけだと 56k が 36k にしかならないものが、 最適化すると 17k 。 まずまずだ。

以下の不具合は head版 ocamljsでは発生しなくなっています。Jakeに感謝!

ocamljsからコードを生成してclosure compilerを通すと動作しなくなる

しかし ocamljsから生成してclosure compilerを通したソースをロードすると

TypeError: Result of expression 'd.apply' [undefined] is not a function.

というエラーが出る(SIMPLE_OPTIMIZATION時。 --compilation_level WHITESPACE_ONLY でスペースを削除するだけならばうまくいく)。

これは、ocamljsが生成したコードに 一部 closure compiler が対応していないのが原因だった。
以下に closure compiler が期待通り動作するように修正する方法を書く。

修正方法

  1. Javaコンパイラとantを準備する.
  2. closure compilerのソースをダウンロードする.
  3. src/com/google/javascript/jscomp/RemoveUnusedVars.java から
    for (Scope fnScope : allFunctionScopes) {
      removeUnreferencedFunctionArgs(fnScope);
    }

の三行をコメントアウトする。
→ ant でビルドする

原因

ocamljsがカリー化された関数を呼び出すとき、 関数の引数の数を表す length プロパティを用いるが、 closure compiler は関数の未使用の引数を削除してしまうので、lengthプロパティの値が変わってしまうのが原因。
closure compiler は 関数の引数の数を表す length プロパティの使用に対応していない(変換が意味を保存しない)。
参考: http://code.google.com/p/closure-compiler/issues/detail?id=253

その他

ocamljsは互換性のためブラウザではまず使わない標準ライブラリ関数も含んでいる。さすがに closure compilerではこれらを削除できないようだ。 コンパイル前の段階でこれを削ってしまえばもっと小さくなるだろう。