expressコードリーディング その1 connectを読む

使用するフレームワークのコードはちゃんと読んで理解しとけと偉い人が言ってた気がするのでexpressのコードを読んでみる。

今回読むexpressのバージョンは2.4.3。
GitHub - expressjs/express at 2.4.3: Fast, unopinionated, minimalist web framework for node.

が、その前に依存してるモジュールを読む。expressが依存してるライブラリは以下のようになっている。

"dependencies": {
  "connect": ">= 1.5.1 < 2.0.0",
  "mime": ">= 0.0.1",
  "qs": ">= 0.0.6"
},
"devDependencies": {
  "connect-form": "0.2.1",
  "ejs": "0.4.2",
  "expresso": "0.7.2",
  "hamljs": "0.5.1",
  "jade": "0.11.0",
  "stylus": "0.13.0",
  "should": "0.2.1",
  "express-messages": "0.0.2",
  "node-markdown": ">= 0.0.1",
  "connect-redis": ">= 0.0.1"
},

この中でも特に重要なのがconnectで、expressのapp.use()とかでmiddlewareを設定できるのはこのconnectの機能。なのでまずconnectを読む。connectのバージョンは1.6.0。
GitHub - senchalabs/connect at 1.6.0: Connect is a middleware layer for Node.js

まずコア機能のcreateServer。

var HTTPServer = require('./http').Server
  , HTTPSServer = require('./https').Server

exports = module.exports = createServer;

...

function createServer() {
  if ('object' == typeof arguments[0]) {
    return new HTTPSServer(arguments[0], Array.prototype.slice.call(arguments, 1));
  } else {
    return new HTTPServer(Array.prototype.slice.call(arguments));
  }
};

これは第一引数がオブジェクトだったらHTTPSServer、そうじゃなかったらHTTPServerを呼んでるだけ。こういう風に使うよってコード中のExamplesに書いてあってわかりやすい。

/*
 * Examples:
 *
 * An example HTTP server, accepting several middleware.
 *
 *     var server = connect.createServer(
 *         connect.logger()
 *       , connect.static(__dirname + '/public')
 *     );
 *
 * An HTTPS server, utilizing the same middleware as above.
 *
 *     var server = connect.createServer(
 *         { key: key, cert: cert }
 *       , connect.logger()
 *       , connect.static(__dirname + '/public')
 *     );
 */

最後のほうに

exports.HTTPServer = HTTPServer;
exports.HTTPSServer = HTTPSServer;

って書いてあるので、直接こっち呼んでもよさそう。とりあえず重要なのはhttp.jsとhttps.jsというのがわかった。http.jsは後で読むとして続き。

同梱のmiddlewareのロードのところ。connectのmiddlewareは自由に定義して使えるのがいいところだけど、最初からよく使いそうなのとかは同梱してある。middleware/*.jsがそれら。それのロードをここでやってる。

exports.middleware = {};

fs.readdirSync(__dirname + '/middleware').forEach(function(filename){
  if (/\.js$/.test(filename)) {
    var name = filename.substr(0, filename.lastIndexOf('.'));
    exports.middleware.__defineGetter__(name, function(){
      return require('./middleware/' + name);
    });
  }
});

exports.utils.merge(exports, exports.middleware);

feaddirSyncでファイル名読んで__definGetter__で定義してる。これだけだとconnct.middleware.logger()とか書かないといけないから、utils.mergeでexportsにマージしてconnect.logger()とかできるようにしてる。utilsっていうのはutils.jsにあるユーティリティ関数群。connect以外でも使えそうな便利なのがいっぱい定義されてた。

今回はここまで。次はhttp.jsを読む。