最近になってGoogleのClosure Compiler Serviceを良く使うようになった。今まで使っていたYUI Compressorと比較すると、複数のJavaScriptファイルをまとめて圧縮出来ることと圧縮にとどまらない最適化を行うことも出来ることがメリットで、CSSの圧縮には対応していないことがデメリット。ウェブのUIで圧縮するのは面倒になってきたので、REST APIを利用してウェブのUIと同じようにコメントで設定を記述してコンパイルするPerlスクリプトを書いてみた。タイトル長い!

#!/usr/bin/perl

# gccs.pl - Compile your JavaScript code with Google Closure Compiler Service
# Usage:    gccs.pl < <original file> > <compiled file>
# Author:   Kyo Nagashima <kyo@hail2u.net>, http://hail2u.net/
# License:  MIT license (http://opensource.org/licenses/mit-license.php)
# Modified: 2009-12-12T00:57:02+09:00

use strict;
use warnings;

use JSON;
use LWP::UserAgent;

my @params = (
  "output_info",   "compiled_code",
  "output_format", "json",
);

&main;
exit;

sub main {
  my @code = <STDIN>;
  push @params, "js_code", join("", @code);
  my $idx = 0;
  my $found_metadata = 0;

  while (my $line = $code[$idx++]) {
    if ($line =~ /^\/\/ ==ClosureCompiler==/) {
      $found_metadata = 1;
      last;
    }
  }

  if ($found_metadata) {
    while (my $line = $code[$idx++]) {
      if ($line =~ /^\/\/ ==\/ClosureCompiler==/) {
        last;
      } elsif ($line =~ /^\/\/ @(\S+)\s*(.*)$/) {
        push @params, $1, $2;
      }
    }
  }

  &compile(@params);
}

sub compile {
  my $ua = LWP::UserAgent->new;
  my $res = $ua->post("http://closure-compiler.appspot.com/compile", \@_);

  if ($res->is_success) {
    my $c = from_json($res->decoded_content);

    if (defined $c->{"serverErrors"}) {
      foreach (@{$c->{"serverErrors"}}) {
        warn "Error(" . $_->{"code"} . "): " . $_->{"error"};
      }

      die "Failed to compile";
    } else {
      print $c->{"compiledCode"};
    }
  } else {
    die $res->status_line;
  }
}

使い方は、

$ gccs.pl < original.js > compiled.js

コンパイルするfoobar.jsにはコンパイル設定を書くこともできる(設定を書かなくても圧縮される)。設定は以下のようにコメントとして記述(ウェブUIと同じ)。

// ==ClosureCompiler==
// @code_url          http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.js
// @compilation_level ADVANCED_OPTIMIZATIONS
// ==/ClosureCompiler==

$(function () {
  var who = "Google Closure Compiler Service";
  alert("Hello " + who + "!");
});

細かい設定はAPIリファレンスを参照。code_urlはいくつでも指定できる。compilation_levelはデフォルトでSIMPLE_OPTIMIZATIONSに設定されているので省略可能。パラメータは丸投げなのでリファレンスに載っていない適当なパラメータなども設定できてしまうが、実害はないと思う。結果がJSONで返ってくるとみなしてパースしているので、output_formatは指定しない方が良い。また警告やエラーの出力にはまったく対応していないのでoutput_infowarning_levelを指定しても無意味。

foobar.jsには設定だけ書いても構わない。その場合はcode_urlが必須になる。

// ==ClosureCompiler==
// @code_url          http://google-code-prettify.googlecode.com/svn/trunk/src/prettify.js
// @code_url          http://hail2u.net/scripts/prettify/lang-css.js
// @code_url          http://hail2u.net/scripts/prettify/loader.js
// ==/ClosureCompiler==

以上のように書いただけでもちゃんとコンパイルされる。


Vimから簡単に使えるように$MYVIMRCには以下のように書いた。

" Compile JavaScript file with Google Closure Compiler Service
" :GCCS [<path>]
command! -nargs=? -complete=file GCCS :call s:CompileScript('<args>')

function! s:CompileScript(file)
  if a:file == ''
    silent normal ggVG
    '<,'>!perl -S gccs.pl
    silent normal V
  else
    execute '!perl -S gccs.pl < ' . expand('%') . ' > ' . a:file
  endif
endfunction

コマンドGCCSにファイルのパスが渡されたらそのファイルに出力、そうでない場合は全選択して差し替えるというもの。