JavaScript のコードから、不用な文字を削除してコードのサイズを小さくしようと言う提言。
JavaScript圧縮ツールや難読化ツールを用いれば、比較的簡単にできます。
これは、かなり効果が期待できるので、是非対応したいところ。
難読化ツールだと、バグフィックスが面倒なので、圧縮ツールを使えばいいかと思われます。
オリジナルと別に圧縮したコードをサーバにおいておいて、mod_rewrite
で置き換えてやれば、メンテナンスも問題ないでしょう。
私が、試してみた圧縮ツールはこの辺り。
各ツールの圧縮効率
各ツールの圧縮効率を調べるために Prototype.js 1.5.1 を圧縮してみた。
結果はこんな感じ
圧縮ツール | サイズ | 圧縮比 | gzip圧縮 | 圧縮比 |
---|---|---|---|---|
オリジナル | 96,311 B | – | 22,048 B | 22.89% |
YUI Compressor | 57,882 B | 60.10% | 16,330 B | 16.96% |
jsjuicer | 71,978 B | 74.73% | 18,078 B | 18.77% |
JSMIN | 71,976 B | 74.73% | 18,074 B | 18.77% |
YUI Compressor に一日の長があるようだ。
オリジナルをそのまま gzip 圧縮しても 23% まで小さくなるが、各圧縮ツールで圧縮後 gzip 圧縮すると、どのツールを使用しても 17% 〜 19% くらいのサイズになってしまうことが分かると思う。
これはもう、ツールで圧縮 & gzip圧縮 はやらなければ損ですね。
JavaScript の自動圧縮
これだけだと記事的につまんないので、自動圧縮を考えてみましょう。
Expiresヘッダを追加しよう!、コンポーネントを圧縮しよう!のときに作った add-expires.php
を拡張してみます。
今回は圧縮ツールとして jsjuicer を採用。
ソースをダウンロードしてきて、コンパイルし add-expires.php
と同じディレクトリに保存しておいてください。
<?php $file_found = false; if (isset($_GET['file'])) { $filename = str_replace('http://'.$_SERVER['SERVER_NAME'].'/','/',$_GET['file']); $filename = dirname($_SERVER['SCRIPT_FILENAME']).$filename; $gz_filename = $filename.'.gz'; if (file_exists($gz_filename)) { // gzip 圧縮されたファイルがあれば、そちらを出力 $filename = $gz_filename; header('Content-Encoding: gzip'); $file_found = true; } elseif (file_exists($filename)) { // html, css, js, xml ならば gzip 圧縮して出力 $path_info = pathinfo($filename); switch($path_info['extension']) { case 'js': // JavaScript の場合、jsjuicer によるコードの圧縮 $min_filename = $filename.'.min'; $exec_cmd = dirname($_SERVER['SCRIPT_FILENAME']).'/jsjuicer'; if (!file_exists($min_filename) && file_exists($exec_cmd)) { $exec_cmd .= ' -sdm '.$min_filename.' '.$filename; exec($exec_cmd); } if (file_exists($min_filename)) {$filename = $min_filename;} case 'html': case 'htm': case 'css': // gzip 圧縮ファイルが無い場合、gzip 圧縮する $exec_cmd = '/usr/bin/gzip'; if (!file_exists($gz_filename) && file_exists($exec_cmd)) { $exec_cmd .= ' -c '.$filename.' > '.$gz_filename; exec($exec_cmd); } case 'xml': if (file_exists($gz_filename)) { // gzip 圧縮が成功すれば、そちらを出力 $filename = $gz_filename; header('Content-Encoding: gzip'); } else { // gzip 圧縮が失敗したら、ob_start("ob_gzhandler") で gzip 圧縮転送 ob_start("ob_gzhandler"); } break; default: break; } unset($path_info); $file_found = true; } } if ($file_found) { // ファイルが有った場合、Expires ヘッダ付きで出力 // Last-Modified ヘッダも送信 header('Last-Modified: '.gmdate('D, d M Y H:i:s', filemtime($filename)).' GMT'); // コンテンツの有効期限は 365 日 $offset = 60 * 60 * 24 * 365; header('Expires: '.gmdate('D, d M Y H:i:s', time() + $offset).' GMT'); readfile($filename); } else { // ファイルが無かった場合 404 エラーを返す header('HTTP/1.1 404 Not Found'); } ?>
注意:
このコードにはセキュリティに対する脆弱性が存在しています。
# 生で打ち込むことによって、アクセス権を与えていないファイルにもアクセスできるようになる。
もし、使用する場合はその辺の対策を行ってから使用してください。
JavaScript ファイルの場合、はじめてアクセスされたときに 21 〜 27 行目で jsjuicer によるコード圧縮を行います。
また、JavaScript / html / css の場合、はじめてアクセスされたときに 32 〜 36 行目で gzip 圧縮されたファイルを作成しておきます。
xml も自動で gzip 圧縮しておきたければ、37 行目(case 'xml':
)を 30 行目の後ろに移動すればOK。
注意しなければいけないのは JavaScript / html / css の内容が変わったときに対応する *.min, *.gz ファイルを手動で削除しておかなければいけないこと。
また、ここまでやったのであれば .htaccess
も以下のように修正して *.min, *.gz がある場合は、php を呼び出さないようにしたほうがより良いでしょう。
<IfModule mod_rewrite.c> RewriteEngine On RewriteBase / RewriteCond %{HTTP:Accept-Encoding} gzip RewriteCond %{REQUEST_FILENAME} "\.(html?|js|css)$" RewriteCond %{REQUEST_FILENAME} !"\.gz$" RewriteCond %{REQUEST_FILENAME}\.gz -s RewriteRule .+ %{REQUEST_URI}.gz [L] RewriteCond %{HTTP:Accept-Encoding} !gzip RewriteCond %{REQUEST_FILENAME} "\.(js)$" RewriteCond %{REQUEST_FILENAME} !"\.min$" RewriteCond %{REQUEST_FILENAME}\.min -s RewriteRule .+ %{REQUEST_URI}.min [L] RewriteCond %{REQUEST_FILENAME} "\.(jpe?g|gif|png|html?|xml|rdf|rss|xsl|css|js|3gp|asf|avi|mp4|mpg|mov|rm|swf|flv|wmv)$" RewriteRule .+ /add-expires.php?file=%{REQUEST_URI} [L] </IfModule>
java が使えるサーバならば jsjuicer の代わりに YUI Compressor を使うのもオススメ。
こちらは JavaScript だけでなく CSS のコードも圧縮してくれます。
# 私は CSS に関しては手動でコード圧縮して対応しました (^^;;