Express4のプロジェクトをTypeScript用に作ってみた
Node.js Toolkit for Visual Studio(RC2)では、JavaScript用にはExpress4のテンプレートが用意されてますが、TypeScript用にはExpress3のテンプレートしか用意されていません。
てことで、TypeScript用にExpress4のプロジェクトを作る手順の備忘録です。
以下の手順では、
npmで、express-generatorとtsdがインストール済みの状態として書いてます。
手順
express-generatorでプロジェクトの雛形作成
適当なフォルダでコンソールを開き、express-generatorを使って雛形を生成します。
express Express4App -e
自分は普段ejsを使ってるので、-eオプションを付けて、ejsを使用する雛形を生成しました。
TypeScript用のNode.jsプロジェクト作成
VSの新規プロジェクト作成ダイアログで、TypeScriptのタブから「Blank Node.js Console Application」を選び、プロジェクトを作成します。
※「From Existing Node.js code」テンプレートについて
既存のNode.jsファイルからVSのプロジェクトを作成するための、「From Existing Node.js code」というテンプレートがありますが、
これを使うと、JavaScriptのプロジェクトとなってしまうので、普通にTypeScriptの新規のプロジェクトとして作ります。
雛形コードのコピー
プロジェクトを作ったら、先ほどexpress-generatorで生成された雛形を、作ったプロジェクトの中にコピーします。
package.jsonは上書きコピーしてしまいます。
また、VSで作ったプロジェクトではjsではなくtsを使用するので、雛形のapp.jsのコードを、app.tsにコピーします。
コピーしたファイルをソリューションに含める
ソリューションエクスプローラからbin/public/routes/viewsのフォルダを選び、右クリックメニューで「プロジェクトに含める」としておきましょう。
スタートアップ・ファイルの設定
express-generatorで生成された雛形は、bin/wwwに書かれているスクリプトを、スタートアップ用のファイルとして指定する必要があります。
ということで、プロジェクトのプロパティで、スタートアップファイルの設定を行います。
また、以下のプロパティも設定して、実行時にブラウザを自動的に開くようにしましょう。
ここでは、起動時に指定するポートは3000としています。
(この値は、先ほどのbin/wwwの中で書かれています。)
依存パッケージのインストール
このままでは必要なパッケージがインストールされてません。
VSの右クリックメニューから「Install Missing npm Packages」というのを実行し、依存パッケージのインストールをします。
TypeScript用の型定義ファイルの用意
tsdを使って型定義ファイルを取得します。
tsdでそのまま型定義のインストールをすると、tsd.jsonなどのある場所と同階層にtypingsフォルダを作り、その中に各ライブラリの型定義ファイルをインストールしていきます。
しかし、VSで作成したプロジェクトファイルでは、Script/typingsディレクトリ配下に型定義ファイルをインストールするので、この形になるように、tsd.jsonファイルを修正して使います。
まずは、tsd.jsonを作ります。
プロジェクトファイルのあるディレクトリでコンソールを開き、以下のコマンドを実行します。
tsd init
ここで作られたjsonファイルを少し修正します。
pathとbundleの項目を追加/修正し、Scripts/typingsディレクトリ以下で型定義ファイルを管理するようにしています。
tsd.json
{ "version": "v4", "repo": "borisyankov/DefinitelyTyped", "ref": "master", "path": "Scripts/typings", "bundle": "Scripts/typings/tsd.d.ts", "installed": {} }
そして、以下のコマンドでexpressの型定義ファイルをインストールします。
tsd query express -rosa install
(この時、元々あったnode.d.tsファイルも更新されます。NTVSのプロジェクトで用意される型定義ファイルは、v0.10向けのファイルですが、最新版を取ってくると、v0.12向けの型定義ファイルがインストールされます。)
この手順で追加された型定義ファイルも、ソリューションエクスプローラの右クリックメニューから、プロジェクトに含めておきましょう。
app.tsのコードを微修正
雛形をそのまま持ってきただけでは、TypeScriptのコンパイルでエラーが出る箇所があります。
ビルドできるような最小限の修正は以下の一か所。
30行目のError型のオブジェクトを作ってる部分を以下のようにany型として受けるように修正します。
var err:any = new Error('Not Found');
よりTypeScriptらしく書くのであれば、以下のようにrequireを呼ぶところでimportで受けたり、関数定義部分で型を指定したりします。
favicon/logger/cookieParser/bodyParserの部分はvarで受けています。
この辺もimportで受けたい場合は、それぞれ対応するライブラリの型定義ファイルをtsdで取ってくればよさそうです。
(ただし、この辺のモジュールはapp.useに突っ込んでるだけで、あまり型定義の必要性を感じなかったのでそのままにしてます。)
修正したコードは以下の通り。
app.ts
import express = require('express'); import path = require('path'); var favicon = require('serve-favicon'); var logger = require('morgan'); var cookieParser = require('cookie-parser'); var bodyParser = require('body-parser'); var routes = require('./routes/index'); var users = require('./routes/users'); var app = express(); // view engine setup app.set('views', path.join(__dirname, 'views')); app.set('view engine', 'ejs'); // uncomment after placing your favicon in /public //app.use(favicon(__dirname + '/public/favicon.ico')); app.use(logger('dev')); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: false })); app.use(cookieParser()); app.use(express.static(path.join(__dirname, 'public'))); app.use('/', routes); app.use('/users', users); // catch 404 and forward to error handler app.use(function (req: express.Request, res: express.Response, next: Function) { var err:any = new Error('Not Found'); err.status = 404; next(err); }); // error handlers // development error handler // will print stacktrace if (app.get('env') === 'development') { app.use(function (err: any, req: express.Request, res: express.Response, next: Function) { res.status(err.status || 500); res.render('error', { message: err.message, error: err }); }); } // production error handler // no stacktraces leaked to user app.use(function (err: any, req: express.Request, res: express.Response, next: Function) { res.status(err.status || 500); res.render('error', { message: err.message, error: {} }); }); module.exports = app;
index.js/user.jsも、TypeScriptの○○.tsというファイルを作り、それぞれ以下のようなコードにします。
index.ts
import express = require('express'); var router = express.Router(); /* GET home page. */ router.get('/', function(req: express.Request, res: express.Response, next: Function) { res.render('index', { title: 'Express' }); }); module.exports = router;
user.ts
import express = require('express'); var router = express.Router(); /* GET users listing. */ router.get('/', function(req: express.Request, res: express.Response, next: Function) { res.send('respond with a resource'); }); module.exports = router;
元からあった○○.jsファイルの拡張子を変えて使う場合は、ビルドアクションがTypeScriptCompileになっていることを確認しておきましょう。
(ここがCompileのままだと、TypeScriptとしてコンパイルされません。)
出来上がったプロジェクト
全体のプロジェクトの構造
以上の手順をやると、以下のような構造のプロジェクトが出来上がります。
実行してみると、こんな風にExpressの雛形のページが表示されるようになります。