Express 4への移行

概要

Express 4は、Express 3からの破壊的変更です。つまり、依存関係にExpressのバージョンを更新すると、既存のExpress 3アプリは動作しません。

この記事では、以下について説明します。

Express 4での変更点

Express 4にはいくつかの重要な変更点があります。

参照

Expressコアとミドルウェアシステムの変更点

Express 4はConnectに依存しなくなり、express.static関数以外、すべての組み込みミドルウェアをコアから削除しました。つまり、Expressは独立したルーティングおよびミドルウェアのWebフレームワークになり、Expressのバージョン管理とリリースはミドルウェアのアップデートの影響を受けなくなりました。

組み込みミドルウェアがないため、アプリの実行に必要なすべてのミドルウェアを明示的に追加する必要があります。以下の手順に従ってください。

  1. モジュールのインストール: npm install --save <module-name>
  2. アプリでモジュールをrequireする: require('module-name')
  3. ドキュメントに従ってモジュールを使用する: app.use( ... )

次の表に、Express 3ミドルウェアとそのExpress 4での対応物を示します。

Express 3Express 4
express.bodyParser body-parser + multer
express.compress compression
express.cookieSession cookie-session
express.cookieParser cookie-parser
express.logger morgan
express.session express-session
express.favicon serve-favicon
express.responseTime response-time
express.errorHandler errorhandler
express.methodOverride method-override
express.timeout connect-timeout
express.vhost vhost
express.csrf csurf
express.directory serve-index
express.static serve-static

Express 4ミドルウェアの完全なリストはこちらです。

ほとんどの場合、古いバージョン3のミドルウェアをExpress 4の対応物に置き換えるだけで済みます。詳細は、GitHubのモジュールドキュメントを参照してください。

app.useはパラメータを受け入れます

バージョン4では、変数パラメータを使用してミドルウェア関数がロードされるパスを定義し、ルートハンドラーからパラメータの値を読み取ることができます。例:

app.use('/book/:id', (req, res, next) => {
  console.log('ID:', req.params.id)
  next()
})

ルーティングシステム

アプリは現在、ルーティングミドルウェアを暗黙的にロードするため、routerミドルウェアに関してミドルウェアのロード順序を気にする必要がなくなりました。

ルートを定義する方法は変更されていませんが、ルーティングシステムには、ルートの整理に役立つ2つの新機能があります。

app.route()メソッド

新しいapp.route()メソッドを使用すると、ルートパスに対してチェーン可能なルートハンドラーを作成できます。パスは1か所で指定されるため、モジュール化されたルートの作成、冗長性とタイプミスを減らすのに役立ちます。ルートの詳細については、Router()ドキュメントを参照してください。

app.route()関数を使用して定義された、チェーンされたルートハンドラーの例を次に示します。

app.route('/book')
  .get((req, res) => {
    res.send('Get a random book')
  })
  .post((req, res) => {
    res.send('Add a book')
  })
  .put((req, res) => {
    res.send('Update the book')
  })

express.Routerクラス

ルートの整理に役立つもう1つの機能は、新しいクラスexpress.Routerです。これを使用して、モジュール化可能なマウント可能なルートハンドラーを作成できます。Routerインスタンスは完全なミドルウェアとルーティングシステムであるため、「ミニアプリ」と呼ばれることがよくあります。

次の例では、モジュールとしてルーターを作成し、ミドルウェアをロードし、いくつかのルートを定義し、メインアプリのパスにマウントします。

たとえば、アプリディレクトリにbirds.jsという名前のルーターファイルを作成し、次の内容を記述します。

var express = require('express')
var router = express.Router()

// middleware specific to this router
router.use((req, res, next) => {
  console.log('Time: ', Date.now())
  next()
})
// define the home page route
router.get('/', (req, res) => {
  res.send('Birds home page')
})
// define the about route
router.get('/about', (req, res) => {
  res.send('About birds')
})

module.exports = router

次に、アプリでルーターモジュールをロードします。

var birds = require('./birds')

// ...

app.use('/birds', birds)

これで、アプリは/birds/birds/aboutパスへのリクエストを処理できるようになり、ルートに固有のtimeLogミドルウェアを呼び出します。

その他の変更点

次の表に、Express 4におけるその他の小さな変更点(ただし重要な変更点)を示します。

オブジェクト 説明
Node.js Express 4はNode.js 0.10.x以降を必要とし、Node.js 0.8.xのサポートを終了しました。

http.createServer()

直接操作する必要がある場合(socket.io/SPDY/HTTPS)を除き、httpモジュールは不要になりました。アプリはapp.listen()関数を使用して起動できます。

app.configure()

app.configure()関数は削除されました。process.env.NODE_ENVまたはapp.get('env')関数を使用して環境を検出し、それに応じてアプリを構成してください。

json spaces

Express 4では、json spacesアプリケーションプロパティはデフォルトで無効になっています。

req.accepted()

req.accepts()req.acceptsEncodings()req.acceptsCharsets()req.acceptsLanguages()を使用してください。

res.location()

相対URLは解決されなくなりました。

req.params

配列でしたが、オブジェクトになりました。

res.locals

関数でしたが、オブジェクトになりました。

res.headerSent

res.headersSentに変更されました。

app.route

app.mountpathとして利用可能になりました。

res.on('header')

削除されました。

res.charset

削除されました。

res.setHeader('Set-Cookie', val)

機能は、基本的なCookie値の設定に限定されています。追加機能にはres.cookie()を使用してください。

アプリ移行の例

Express 3アプリケーションをExpress 4に移行する例を次に示します。対象となるファイルはapp.jspackage.jsonです。

バージョン3アプリ

app.js

次のapp.jsファイルを持つExpress v.3アプリケーションを検討してください。

var express = require('express')
var routes = require('./routes')
var user = require('./routes/user')
var http = require('http')
var path = require('path')

var app = express()

// all environments
app.set('port', process.env.PORT || 3000)
app.set('views', path.join(__dirname, 'views'))
app.set('view engine', 'pug')
app.use(express.favicon())
app.use(express.logger('dev'))
app.use(express.methodOverride())
app.use(express.session({ secret: 'your secret here' }))
app.use(express.bodyParser())
app.use(app.router)
app.use(express.static(path.join(__dirname, 'public')))

// development only
if (app.get('env') === 'development') {
  app.use(express.errorHandler())
}

app.get('/', routes.index)
app.get('/users', user.list)

http.createServer(app).listen(app.get('port'), () => {
  console.log('Express server listening on port ' + app.get('port'))
})

package.json

それに対応するバージョン3のpackage.jsonファイルは、次のようになります。

{
  "name": "application-name",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "start": "node app.js"
  },
  "dependencies": {
    "express": "3.12.0",
    "pug": "*"
  }
}

プロセス

移行プロセスを開始するには、Express 4アプリに必要なミドルウェアをインストールし、次のコマンドを使用してExpressとPugをそれぞれの最新バージョンに更新します。

$ npm install serve-favicon morgan method-override express-session body-parser multer errorhandler express@latest pug@latest --save

app.jsに以下の変更を加えます。

  1. 組み込みのExpressミドルウェア関数express.faviconexpress.loggerexpress.methodOverrideexpress.sessionexpress.bodyParserexpress.errorHandlerは、expressオブジェクトでは使用できなくなりました。代替物を手動でインストールし、アプリにロードする必要があります。

  2. app.router関数をロードする必要はありません。有効なExpress 4アプリオブジェクトではないため、app.use(app.router);コードを削除します。

  3. ミドルウェア関数を正しい順序でロードしてください。アプリルートのロード後にerrorHandlerをロードします。

バージョン4アプリ

package.json

上記のnpmコマンドを実行すると、package.jsonが次のように更新されます。

{
  "name": "application-name",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "start": "node app.js"
  },
  "dependencies": {
    "body-parser": "^1.5.2",
    "errorhandler": "^1.1.1",
    "express": "^4.8.0",
    "express-session": "^1.7.2",
    "pug": "^2.0.0",
    "method-override": "^2.1.2",
    "morgan": "^1.2.2",
    "multer": "^0.1.3",
    "serve-favicon": "^2.0.1"
  }
}

app.js

次に、無効なコードを削除し、必要なミドルウェアをロードし、必要に応じてその他の変更を加えます。app.jsファイルは次のようになります。

var http = require('http')
var express = require('express')
var routes = require('./routes')
var user = require('./routes/user')
var path = require('path')

var favicon = require('serve-favicon')
var logger = require('morgan')
var methodOverride = require('method-override')
var session = require('express-session')
var bodyParser = require('body-parser')
var multer = require('multer')
var errorHandler = require('errorhandler')

var app = express()

// all environments
app.set('port', process.env.PORT || 3000)
app.set('views', path.join(__dirname, 'views'))
app.set('view engine', 'pug')
app.use(favicon(path.join(__dirname, '/public/favicon.ico')))
app.use(logger('dev'))
app.use(methodOverride())
app.use(session({
  resave: true,
  saveUninitialized: true,
  secret: 'uwotm8'
}))
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({ extended: true }))
app.use(multer())
app.use(express.static(path.join(__dirname, 'public')))

app.get('/', routes.index)
app.get('/users', user.list)

// error handling middleware should be loaded after the loading the routes
if (app.get('env') === 'development') {
  app.use(errorHandler())
}

var server = http.createServer(app)
server.listen(app.get('port'), () => {
  console.log('Express server listening on port ' + app.get('port'))
})

httpモジュール(socket.io/SPDY/HTTPS)を直接操作する必要がない限り、ロードする必要はなく、アプリは次のように簡単に起動できます。

app.listen(app.get('port'), () => {
  console.log('Express server listening on port ' + app.get('port'))
})

アプリの実行

移行プロセスが完了し、アプリはExpress 4アプリになりました。確認するには、次のコマンドを使用してアプリを起動します。

$ node .

https://127.0.0.1:3000にアクセスし、Express 4によってレンダリングされたホームページが表示されることを確認します。

Express 4アプリジェネレーターへのアップグレード

Expressアプリを生成するコマンドラインツールは依然としてexpressですが、新しいバージョンにアップグレードするには、Express 3アプリジェネレーターをアンインストールしてから、新しいexpress-generatorをインストールする必要があります。

インストール

システムにExpress 3アプリジェネレーターが既にインストールされている場合は、アンインストールする必要があります。

$ npm uninstall -g express

ファイルとディレクトリの権限の構成方法によっては、このコマンドをsudoで実行する必要がある場合があります。

新しいジェネレーターをインストールします。

$ npm install -g express-generator

ファイルとディレクトリの権限の構成方法によっては、このコマンドをsudoで実行する必要がある場合があります。

これで、システム上のexpressコマンドがExpress 4ジェネレーターに更新されました。

アプリジェネレーターの変更点

コマンドオプションと使い方はほぼ同じですが、次の例外があります。

次のコマンドを実行して、Express 4アプリを作成します。

$ express app4

app4/app.jsファイルの内容を見ると、アプリに必要なすべてのミドルウェア関数(express.staticを除く)が独立したモジュールとしてロードされており、routerミドルウェアはアプリで明示的にロードされなくなっていることがわかります。

また、古いジェネレーターによって生成されたスタンドアロンアプリとは異なり、app.jsファイルがNode.jsモジュールになっていることもわかります。

依存関係をインストールした後、次のコマンドを使用してアプリを起動します。

$ npm start

package.jsonファイルのnpm startスクリプトを見ると、アプリを起動する実際のコマンドはnode ./bin/wwwであり、Express 3ではnode app.jsだったことがわかります。

Express 4ジェネレーターによって生成されたapp.jsファイルはNode.jsモジュールになったため、(コードを変更しない限り)アプリとして独立して起動できなくなりました。モジュールはNode.jsファイルにロードする必要があり、Node.jsファイルから起動する必要があります。この場合、Node.jsファイルは./bin/wwwです。

Expressアプリの作成やアプリの起動にbinディレクトリや拡張子なしのwwwファイルは必須ではありません。ジェネレーターによる単なる提案なので、必要に応じて自由に修正してください。

wwwディレクトリを削除し、「Express 3の方法」を維持するには、app.jsファイルの末尾にあるmodule.exports = app;という行を削除し、次のコードを貼り付けます。

app.set('port', process.env.PORT || 3000)

var server = app.listen(app.get('port'), () => {
  debug('Express server listening on port ' + server.address().port)
})

次のコードを使用して、app.jsファイルの先頭でdebugモジュールをロードしてください。

var debug = require('debug')('app4')

次に、package.jsonファイルの"start": "node ./bin/www""start": "node app.js"に変更します。

これで、./bin/wwwの機能をapp.jsに戻しました。この変更はお勧めしませんが、この演習は、./bin/wwwファイルの動作と、app.jsファイルが単独で起動しなくなった理由を理解するのに役立ちます。