Expressでプロジェクトを作成する時は基本express-generatorを使っている。yarn init
からexpress
をインストールしてExpressプロジェクトを作成しようとした時に、そういえばどうしてたっけ?となったので、改めてexpress-generator
がやっていることを再確認して書きとめておこうと思います。
NodeJSの基本的なことなので内容は特に難しくはないです。
bin/www
bin/www
はサーバー起動のファイルですね。実際にyarn start
のnpmスクリプトはnode ./bin/www
となっています。
さて、bin/www
の中身ですが次のようになっています。
// bin/www
var app = require('../app');
var debug = require('debug')('express-app:server');
var http = require('http');
var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);
var server = http.createServer(app);
server.listen(port);
server.on('error', onError);
server.on('listening', onListening);
function normalizePort(val) {
var port = parseInt(val, 10);
if (isNaN(port)) {
// named pipe
return val;
}
if (port >= 0) {
// port number
return port;
}
return false;
}
function onError(error) {
if (error.syscall !== 'listen') {
throw error;
}
var bind = typeof port === 'string'
? 'Pipe ' + port
: 'Port ' + port;
switch (error.code) {
case 'EACCES':
console.error(bind + ' requires elevated privileges');
process.exit(1);
break;
case 'EADDRINUSE':
console.error(bind + ' is already in use');
process.exit(1);
break;
default:
throw error;
}
}
function onListening() {
var addr = server.address();
var bind = typeof addr === 'string'
? 'pipe ' + addr
: 'port ' + addr.port;
debug('Listening on ' + bind);
}
アプリのメイン処理はapp.js
でモジュール化しているので、それを読み込んでvar server = http.createServer(app);
でHTTPサーバーを用意しています。
実はhttp
モジュールを使わなくてもapp.listen(port)
でサーバーを起動することができます。ただ、socket.ioやHTTPS(実際はhttps
を使う)を利用を考えると、結局http
モジュールを使うことになるかとは思います。
process.env.PORT
は本番環境で環境変数PORTにポート番号を設定していた時にそのポートでサーバーが起動するようにしています。無ければ3000番のポートで動きます。開発環境でlocalhost:3000
がデフォルトなのはここによるものですね。
normalizePort
は環境変数の設定が正しいか見ているだけです。文字列でもOKで、設定がダメならfalse
が返ってくるのでサーバーが起動せずにエラーになるだけですね。
app.set('port', port);
はちょっと用途がわからないですね。ポート番号を定数で持つようにしていますが、どこにも使ってないので必要なさそう。もしかしたらモジュール内部で必要なのかもしれないです。
server.on()
で各イベントにイベントハンドラーを設定しています。
エラーイベントは、EACCES (Permission denied)
とEADDRINUSE (Address already in use)
の場合だけそれぞれのメッセージをログに出力し、それ以外の場合は例外を投げています。
リスナーイベントは動作しているURLを出力するようになっています。
app.js
app.js
はサーバーのメイン処理が記載されています。express-generator
を使う時もここは触るので、自動生成頼りにしている機能だけ見ていきます。
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var app = express();
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', indexRouter);
app.use('/users', usersRouter);
app.use(function(req, res, next) {
next(createError(404));
});
app.use(function(err, req, res, next) {
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
コード上部はミドルウェア群の読み込みですね。
-
http-errors
- エラーオブジェクトを作ってくれるミドルウェア。
-
path
- ファイルやディレクトリのパスの扱いでよく使うやつですね。
-
cookie-parser
- ヘッダー情報からクッキーを拾ってくれる。
-
morgan
- HTTPリクエストのログを出力してくれるミドルウェア。
app.set
は通常は定数の定義ですが、いくつかのプロパティは特別な意味を持ちます。views
やview engine
はその一例です。
views
は描画ファイルを格納するディレクトリパスを設定するプロパティで、自動生成ではpath.join(__dirname, 'views')
としてプロジェクト配下の/views
ディレクトリを指定しています。
view engine
はレンプレートエンジンの拡張子を設定します。Expressの標準はPug(元Jade)です。
app.use
は使用するミドルウェアをマウントします。読み込んだミドルウェアはここで設定しています。
express.json()
はJSONを扱うミドルウェアでExpress v4.16.0から利用できます。それ以前はbody-parse.json()
を使う必要があります。
express.urlencoded({ extended: false })
はURL解析、クエリパラメータとかを扱います。これもExpress v4.16.0以降で利用可です。
express.static(path.join(__dirname, 'public'))
は静的ファイルの置き場を指定しています。
あとがき
express-generator
がやっていることは最低限ですが毎回書くのは面倒なところを自動生成してくれます。始めにも言いましたが、一から用意しようとした時に何必要だっけ?となるのでありがたい。というかexpress-generator
で作成して必要な形に直す方が早いですね。