スタティックサイトのgzip最適化(まとめ)

## 全体の流れ

サーバの静的ファイルコンテンツはgzip圧縮を利用することによりパフォーマンスを改善できます。方法は大きく分けて2通りありますが、まずポイントをまとめておきます。

* リクエスト時にサーバサイドでgzip圧縮して返す
    * 設定が簡単
    * しかしサーバサイドでCPUリソースを消費する(最適な方法ではない)
* 事前にgzip圧縮したファイルを用意しておきそれを返す
    * パフォーマンスはこれが最適
    * 自分でgzip圧縮する手間が掛かる(しかし次第で自動化は可能)

> サーバ側の専門知識がある人ならこの説明で十分だと思います。分からない読者(自分もほんの2-3年前までそうでした)にはできるだけ初心者にも分かるような詳しい解説を書きましたので参考にして下さい。
> 
> [Apacheサーバのgzip圧縮最適化(1-4)](http://huguma.hatenablog.com/entry/2015/11/26/194839)

事前圧縮する場合は元ファイルを残すかどうかの有無で2通りの方法があります。ここも要点をまとめます。

* サーバのCPUリソースを最小化する場合は元ファイルを残す
    * ただしファイル数が倍になり、ディスク使用量も増える
* ディスクリソースを最小化する場合は元ファイルを消去する
    * 圧縮ファイルだけ残すためディスク容量を大幅に削減できる
    * 非圧縮を返すようリクエストされた場合にファイル展開のためCPUを消費するが...
        * 展開のCPU負荷は圧縮よりはるかに低い
        * 今のブラウザは全て圧縮形式でリクエストするため非圧縮の要求はまれ
* 以上を総合的に考慮すると今では消去する方が有利

今回はApacheを利用する機会があったので少し詳しく調査しました。他の場合も多少知識がありますのでここで全体的にまとめておきたいと思います。

## Apache

Apacheは意外と設定が難解で、まとまった資料が見つからなかったので今回は自分で調べました。Apache 2.4で動作確認した文例を示します。これを参考に各自必要な部分を変更すれば大体の用途には対応できると思います。

> より詳しい説明は自分のブログに書いておきました。設定(ディレクティブ)の意味まで知りたい方はご覧下さい。
> 
> [Apacheサーバのgzip圧縮最適化: 2. 設定方法](http://huguma.hatenablog.com/entry/2015/11/26/200715)

### サーバサイド圧縮の場合

#### (1) 特定ファイルタイプだけ圧縮

``` apache
AddOutputFilterByType DEFLATE text/html text/plain
```

#### (2) 特定ファイルタイプ(拡張子)以外を圧縮

``` apache
SetOutputFilter DEFLATE
SetEnvIfNoCase Request_URI \.(?:gz|gif|jpg|png)$ no-gzip
```

### 事前gzip圧縮する場合

#### (1) 元ファイルを残す

``` apache
RewriteEngine on
RewriteCond %{HTTP:Accept-Encoding} gzip
RewriteCond %{REQUEST_URI} \.(?:html|css)$
RewriteCond %{REQUEST_FILENAME}.gz -s
RewriteRule .* %{REQUEST_URI}.gz [L]

<FilesMatch "\.html\.gz$">
  ForceType text/html
</FilesMatch>
<FilesMatch "\.css\.gz$">
  ForceType text/css
</FilesMatch>
```

#### (2) 元ファイルを消去する

``` apache
Options +MultiViews
MultiviewsMatch Any
FilterDeclare gzip CONTENT_SET
FilterProvider gzip inflate "%{req:Accept-Encoding} !~ /gzip/"
FilterChain gzip

<FilesMatch "\.html\.gz$">
  ForceType text/html
</FilesMatch>
<FilesMatch "\.css\.gz$">
  ForceType text/css
</FilesMatch>
```

## Nginx

こちらは専門家の方が書いたよい解説がありますので次をご覧下さい。

[nginxパフォーマンスチューニング〜静的コンテンツ配信編〜](http://qiita.com/cubicdaiya/items/2763ba2240476ab1d9dd)

## Webアプリケーションの場合

Webアプリケーションフレームワークの中でも部分的にstaticに取り扱うケースがありますので、言語別に簡単にまとめてみようと思います。まず(私が唯一詳しい)Rubyについて説明し、その他の言語は概略だけ示します。

### Ruby

RubyベースのWebアプリケーションフレームワーク(Ruby on RailやSinatraなど)ではHTTPとアプリケーション間のインターフェースとしてRack(ライブラリ)を用います。

* [Sinatra学習の基礎としてRackを学ぶ](http://d.hatena.ne.jp/riocampos+tech/20150201/study_rack_and_sinatra) - 豊富なリンク集(ここを基点に調べれば間違いなし)
* [Rack解説 - Rackの構造とRack DSL](http://qiita.com/higuma/items/838f4f58bc4a0645950a) - 入門者向け解説(2年近く前に書きました)

Rackの標準ミドルウエアにサーバサイドgzip圧縮用の__Rack::Deflater__があります。事前圧縮用クラスは当時なかったので__rack-gzip-static__というgemを作りました(今でもSinatra用にはいいかも...)。当時書いた解説がありますのでご覧下さい。

[Rack応用 - HTTP圧縮エンコーディング最適化](http://qiita.com/higuma/items/9b841aca5f3d58a2b5aa)

Ruby on Railは4.2からActiveSupportにgzipが組み込まれ、直接扱えるようになりました。一時はアセットパイプラインにgzip事前圧縮が内蔵され、assetsのプリコンパイル時に自動生成していたようです。2015/12時点では次にその記述が残っています。

[Rails Guides(和訳) - アセットパイプライン (Gzip圧縮)](http://railsguides.jp/asset_pipeline.html#gzip圧縮)

しかしすぐに仕様が変わってしまうのもまたRailsの常で、現バージョンではこの機能は廃止されています。

[GitHub Issues - Enable gzip on sprockets 3.0](https://github.com/rails/sprockets/issues/26)

自分で小さなコードを追加すれば対応可能です(次を参考にして下さい)。

[Stack Overflow - missing gzip version of css and js assets](http://stackoverflow.com/questions/29700369/missing-gzip-version-of-css-and-js-assets)

なおRails 4.2以前のバージョンではgemの__rack-zippy__を利用可能です。

<https://rubygems.org/gems/rack-zippy/>

### その他の言語/フレームワーク

Node.jsにはHTTPインターフェースのConnectがあり、WebフレームワークのExpressで用いられています(RubyにおけるRackとSinatraの関係とよく似ています)。gzip圧縮に関するミドルウエアは一通り揃っています。

* [compression](https://www.npmjs.com/package/compression) - サーバサイド圧縮用(標準)
* [connect-gzip-static](https://www.npmjs.com/package/connect-gzip-static) - 事前圧縮用(外部モジュール)

PythonのDjangoには専用のミドルウエア機構があり、ミドルウエアコンポーネントのひとつにGzipがあります(あまり詳しくないので紹介のみ)。

<https://docs.djangoproject.com/en/1.9/ref/middleware/#module-django.middleware.gzip>

調べたところCakePHPにもあります(これも紹介のみ)。

<https://github.com/josegonzalez/cakephp-gzip>