express-generatorがやってくれていることを再確認する

Expressでプロジェクトを作成する時は基本[express-generator](https://github.com/expressjs/generator)を使っている。`yarn init`から`express`をインストールしてExpressプロジェクトを作成しようとした時に、そういえばどうしてたっけ？となったので、改めて`express-generator`がやっていることを再確認して書きとめておこうと思います。
NodeJSの基本的なことなので内容は特に難しくはないです。

## bin/www

`bin/www`はサーバー起動のファイルですね。実際に`yarn start`のnpmスクリプトは`node ./bin/www`となっています。  
さて、`bin/www`の中身ですが次のようになっています。  

```javascript
// 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`を使う時もここは触るので、自動生成頼りにしている機能だけ見ていきます。  

```app.js

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](https://github.com/jshttp/http-errors)  
  - エラーオブジェクトを作ってくれるミドルウェア。
- [path](https://nodejs.org/api/path.html)
  - ファイルやディレクトリのパスの扱いでよく使うやつですね。
- [cookie-parser](https://github.com/expressjs/cookie-parser)
  - ヘッダー情報からクッキーを拾ってくれる。
- [morgan](https://github.com/expressjs/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`で作成して必要な形に直す方が早いですね。

## 参考サイト

- [Express 4.x - API リファレンス](http://expressjs.com/ja/api.html)
- [Express 4 への移行](https://expressjs.com/ja/guide/migrating-4.html)
- [error_syscall](https://nodejs.org/api/errors.html#errors_error_syscall)
- [Node.js Error Codes](https://nodejs.org/api/errors.html#nodejs-error-codes)