Express読んだ

Node.jsのWebアプリケーションフレームワークexpressのソースコードを読んだ。

Node.jsの書き方とかHTTPの仕様とか調べながらコード読んで勉強になった。

読むときに作ったメモを載せておく。テキトーすぎてまったく参考にならないと思う。

依存モジュール

気になったものだけをメモ

connect

ミドルウェアを使って拡張できるHTTPサーバーフレームワーク
便利なmiddlewareが色々入ってる

commander

コマンドパーサーみたいなやつ

range-parser

HTTPヘッダフィールドのrangeをパースするやつ
小さくて読みやすそう

fresh

http response freshnessを調べる単純なやつ
キャッシュ制御につかう

methods

ただのhttp method 一覧

send

static() file server
面白そう

connectを読む

expressはルーティング等の機能がconnectのmiddlewareとして実装されていて、connectに大きく依存する形で作られている。
そのため、expressを理解しようとなるとまずconnectのコードを読んで理解しないといけない。

senchalabs/connect · GitHub

使用例はこんな感じ

var connect = require('connect')
  , http = require('http');

var app = connect()
  .use(connect.favicon())
  .use(connect.logger('dev'))
  .use(connect.static('public'))
  .use(connect.directory('public'))
  .use(connect.cookieParser())
  .use(connect.session({ secret: 'my secret here' }))
  .use(function(req, res){
    res.end('Hello from Connect!\n');
  });

http.createServer(app).listen(3000);

lib/connect.js

ここからはじまる。connect()で呼び出されるのはcreateServer
同梱されてるmiddlewareをロードする

lib/patch.js

http.serverResponseにメソッドを追加する

lib/proto.js

app.useを定義したり
メインっぽい
抽象クラスみたいな感じ
lib/connect.jsから呼び出される

app.use

よく使うやつ
ミドルウェアをstackに積む
middlewareはこんな感じの何かするやつ。nextを呼び出すと次のやつにいく

function(req, res, next) {}
app.handle

リクエストを処理する
stackを下から順に見ていき、routeにマッチしたら実行していく
nextを繰り返す
おもしろい

next

次のミドルウェアに進む
次に処理するものなくなったり、処理が終わったらエラーを出したりとかする

app.listen

http.createServer(app)してlistenするだけ

http.createServer

http.Serverオブジェクトを返す
http.ServerはEventEmitterでリクエストが来るたびに'request'イベントを発火させる
function (request, response) { }
コールバックにはhttp.ServerRequestとhttp.ServerResponseが引数として渡される

createServerには[requestListener]を渡すことができて、自動で登録してくれる

expressを読む

lib/express.js

createApplicationがexposeされてる

connectのミドルウェアをexpress.*として見えるようにしたり

createApplication

connectの上にapplication(lib/application.js)を重ねてinitする

lib/application.js

中心的な処理

app.defaultConfigulation

initが呼び出す
middlewareを設定したり
app.routerを設定したりとか

app.use

connect#use()へのproxy

別のapplicationをmountすることとかもできる

app.engine

引数の拡張子に対して使用するtemplate engineを登録する

中でやってるのはとりあえずプロパティに代入するだけ

app.set

settingに代入するのと、参照するの
app.getの実体もこれ

app.enable

app.setでtrueを代入するだけ

app.disable

app.setでfalseを代入するだけ

app.configure

development, stage, productionなど環境に応じた設定

app.render

template engineで描画する

view.renderを呼び出してる

res.renderで呼び出されたり

lib/router/index.js

Routerがexposeされてる
router.middlewareにmiddlewareが入っていてapplication.jsではこれを使ってる

map

method(getとかpostとか)をキー、Routeオブジェクトの配列を値としたハッシュ

_dispatch

middlewareの実体

requestにマッチするrouteを取り出し
paramを適用したりする

面白かった

param

paramに設定されたcallbackを順番に実効する
たとえば /users/:id で

app.param('id', function(req,res,next,val) { 
  // hoge …..
})

だとこのコールバックに適切なパラメータを渡して実行する

paramのcallbackの実行が終わったら
routeのcallbackを順番に実行する

route

routeを定義する
app.getとかapp.postとかを扱うのはこれ
Routeオブジェクトを作ってRouter#mapに放りこむ

(this.map[method] = this.map[method] || []).push(route);
matchRequest

this.mapからrequestにマッチするrouteを探してきて返す

lib/middleware.js

X-Powered-Byをセットしたり
reqやresを初期化したりするmiddleware

lib/view.js

view.render(option, fn)

engineで描画する

lib/request.js

http.ServerRequestの拡張

lib/response.js

http.ServerResponse
地道な感じ