通常、Socket.ioのクライアントスクリプトは、起動しているサーバー側のURLから「/socket.io/socket.io.js」の様に取得するのだが、どうもこれがMinifyされていない。HTTPヘッダーに「Cache-Control」もついてないし、gzip圧縮転送もされていない。
本番運用向けのクライアントスクリプトに対する設定をしましょう。
Socket.ioのソースコードを眺める
lib/manager.jsを見る限りだと、
, 'browser client': true
, 'browser client cache': true
, 'browser client minification': false
となっている。「browser client minification」をtrueにしてあげれば良いのだろう。
Manager.prototype.enable = function (key) {
this.settings[key] = true;
this.emit('set:' + key, this.settings[key], key);
return this;
};
みたいなことになっているので、このあたりを利用して設定してあげる。
Minifyする
こんな感じにコードを書けば、クライアントスクリプトはMinifyされる。
var io = require('socket.io').listen(80);
io.enable('browser client minification');
ブラウザキャッシュ
Socket.ioのクライアントスクリプトなんて、Socket.ioのバージョンアップしない限りは、コードの中身が変わらないはずなので、HTTPヘッダーに「Cache-Control」などを追加して、ブラウザ側でキャッシュして欲しい。と考えていたところ、こんなつぶやきを発見した。
Socket.IOのクライアントは /socket.io.v.0.8.7.js みたいに呼び出すとブラウザキャッシュに溜まるよ。最近のバージョンで入ったみたいです。
— まどがい (@madogai) November 28, 2011
おぉ!じゃあ、さっそく。このとおり取得すると、残念ながら通常の取得と全く変わってない。
このあたりの作者のやりとりを見てると実装はやっぱりされている。
lib/manager.jsの上部あたりを見ると
, 'browser client cache': true
, 'browser client minification': false
, 'browser client etag': false
, 'browser client expires': 315360000
と設定されているので、Cache-Controlヘッダー付きで配信されてもおかしくないんだけどなぁ。
lib/static.jsがクライアントスクリプトを配信しているコードがかかれているのだろうけど、ここをのぞく限り
// see if we need to set Expire headers because the path is versioned
if (versioned) {
var expires = self.manager.get('browser client expires');
headers['Cache-Control'] = 'private, x-gzip-ok="", max-age=' + expires;
headers['Date'] = new Date().toUTCString();
headers['Expires'] = new Date(Date.now() + (expires * 1000)).toUTCString();
}
と、実際の実装がきちんと書かれている。
this.add('/socket.io.v', { mime: mime.js }, function (path, callback) {
build(self.manager.get('transports'), callback);
});
このあたりで、取得URLに対する処理が書かれているのだろうけど…。と途方に暮れていたところ、
test/static.test.jsで、クライアントスクリプト取得に関するテストが書いてある。コレをのぞいていくと…。
cl.get('/socket.io/socket.io.v0.8.9.js', function (res, data) {
res.headers['content-type'].should.eql('application/javascript');
res.headers['content-length'].should.match(/([0-9]+)/);
res.headers['cache-control']
.indexOf(io.get('browser client expires')).should.be.above(-1);
という、テストを発見!!どうも内容をみると取得方法(バージョンの指定方法)が違うのである。
Socket.IOのクライアントは /socket.io.v.0.8.7.js みたいに呼び出すとブラウザキャッシュに溜まるよ。最近のバージョンで入ったみたいです。
— まどがい (@madogai) November 28, 2011
(*1)
と取得するのは誤りで、正しくは
「/socket.io/socket.io.v0.8.9.js」のように指定するべきである。
動作確認をしたところ、無事にHTTPヘッダーに「Cache-Control」が追加されていた。
Content-Type: application/javascript
Cache-Control: private, x-gzip-ok="", max-age=315360000
Date: Sun, 01 Jan 2012 21:39:35 GMT
Expires: Wed, 29 Dec 2021 21:39:35 GMT
Content-Length: 27339
Connection: keep-alive
gzipも有効にする
ついでだから、gzip圧縮しての転送を有効にしておこう
var io = require('socket.io').listen(80);
io.enable('browser client minification');
io.enable('browser client gzip');
最後に動作確認
/socket.io/socket.io.v0.8.7.js
--> HTTP/1.1 200 OK
Content-Type: application/javascript
Content-Length: 8228
Content-Encoding: gzip
Vary: Accept-Encoding
Connection: keep-alive
Content-Lengthが小さくなってますね。
以上、こんな感じで本番向けのクライアントスクリプトの設定ができました。実際に動作確認することはとても大事です。
ですが、テストコードが実装テストだけに役立つのではないということも知っていただきたいところです。
今回のように期待する動作と結果を追っていくだけでも、テストコードがあると的確に理解することができました。
不確実性のあるコードの意図や雰囲気だけでなく、具体的に動作する情報がテストコードです。
Christian Johansen
|
*1: 単なるtypoなんでしょうが、日本語情報が少ないので…