JavaScriptでWebアプリを開発できる「Node.js」活用入門 3ページ
Node.js向けWebアプリケーションフレームワーク「express」を使う
ApacheやIISといったWebサーバー上でCGIとしてWebアプリケーションを実行させる場合、Webアプリケーション側では基本的には動的なコンテンツの生成のみを行い、画像ファイルやCSSファイルといった静的ファイルへのリクエストについてはWebサーバー側に処理を任すことができた。一方、Node.jsで作成したWebアプリケーションの場合、静的なファイルの配信についてもアプリケーション内で対応しなければならない。このような問題は、Webアプリケーションフレームワークを利用することで容易に解決できる。
近年ではWebアプリケーションを作成する際、Webアプリケーションフレームワークを利用するのが一般的だ。Node.js向けにも多数のWebフレームワークが開発されているが、そのなかでも有名なものが「express」である。expressはURLディスパッチャ、テンプレートエンジン、セッション管理機能、エラーハンドリング、静的ファイルの配信といった機能を備えるWebアプリケーションフレームワークで、npmを使って容易にインストールできる。
npmによるパッケージのインストール
npmでパッケージをインストールするには、「npm install <パッケージ>」のように、「install」オプションに続けてインストールするパッケージ名を指定してnpmを実行する。たとえばexpressモジュールをインストールするには、次のようにする。
npm install express
コマンドを実行すると、必要なパッケージがダウンロードされ、インストールされる(図9)。
|
| 図9 npmコマンドでexpressコマンドをインストールした実行例 |
npmでは、デフォルトではnpmコマンドを実行したディレクトリ以下の「node_modules」ディレクトリにパッケージがインストールされる。そのため、そのモジュールを利用したいファイルが含まれているディレクトリ内でnpmコマンドを実行するのが基本となる。
expressのスケルトンファイルを生成する
expressには、最低限必要なファイルやディレクトリをテンプレートから自動的に生成する機能が備えられている。たとえば「newb」ディレクトリ以下にファイルを生成するには、インストールされたモジュール内の「bin」ディレクトリにある「express」スクリプトをnodeで実行すれば良い(図10)。
> node node_modules\express\bin\express newb
|
| 図10 expressスクリプトを実行してスケルトンファイルを生成する |
スケルトンファイルを生成したら、そのディレクトリに移動して「npm install」コマンドを実行することで、依存するモジュールが自動的にインストールされる(図11)。
> cd newb > npm install
|
| 図11 作成されたディレクトリ内で「npm install」コマンドを実行することで、依存するモジュールがインストールされる |
作成されたファイルおよびディレクトリは表1のとおりだ。
| ファイル/ディレクトリ名 | 説明 |
|---|---|
| node_modules | 依存するモジュールが格納される |
| public | 画像やスクリプト、CSSなどの静的なファイルをここに格納する |
| routes | リクエストされたURLに対応する処理を行うスクリプトが格納される |
| views | テンプレートが格納される |
| app.js | アプリケーションのメインスクリプト |
| package.json | パッケージの情報が記述されたjson形式データファイル |
作成されたアプリケーションの本体となるのがapp.jsファイルだ。このファイルをnodeで実行するとWebアプリケーションが起動する(図12)。また、アプリケーションを終了するにはCtrl-Cを押下すれば良い。
> node app.js
|
| 図12 app.jsがWebアプリケーションの本体となる |
app.jsを実行した状態でWebブラウザで3000番ポートにアクセスすると、その実行結果として図13のような画面が表示される。
|
| 図13 スケルトンの実行結果 |
expressのアーキテクチャ
expressではあらかじめリクエストURLのパス名とそれに対応するハンドラの組み合わせを指定しておくことで、リクエストに対し実行する処理を指定する(ルーティング)。これらの設定はapp.jsファイル内で行われており、デフォルトでは次のように、「/」に対し「routes.index」というハンドラが対応付けられている。
// Routes
app.get('/', routes.index);
ここで参照されている「routes.index」の実体は、routesディレクトリ内のindex.jsファイル内に下記のように記述されている。
exports.index = function(req, res){
res.render('index', { title: 'Express' })
};
これがWebブラウザから「http://<ホスト名>/」というリクエストを受けた際に実行されるコードとなる。コード内の「res.render」は、第1引数で指定されたテンプレートを読み込み、第2引数で指定されたデータを与えてテンプレートのレンダリングを行う、という関数だ。テンプレートは後述する「Jade」というフォーマットで記述されている。
res.render関数はviewsディレクトリ内のlayout.jadeファイルをテンプレートとして読み込み、さらにその「body」部分におなじくviewsディレクトリ内のindex.jadeファイルで記述された本文を挿入する、という動作を行う(リスト3、4)。
リスト3 layout.jadeファイルの中身
!!!
html
head
title= title
link(rel='stylesheet', href='/stylesheets/style.css')
body!= body
リスト4 index.jadeファイルの中身
h1= title
p Welcome to #{title}
以上を簡単にまとめると、次のようになる。
- 「/」というパス名に対する処理は「app.get('/', routes.index);」というコードで定義されている
- 実際の処理は「routes/index.js」内の「exports.index」に与えている匿名関数で定義されている
- exports.indexで定義されている処理内容は「views/index.jade」というテンプレートを呼び出してレンダリングする、というもの
これを踏まえ、たとえば「/foo/」というリクエストに対する処理を追加したい場合は、まずapp.js内に「app.get('/foo/', routes.foo);」というコードを追加する。
app.get('/foo/', routes.foo);
次に「routes/index.js」内に次のようなコードを追加する。
exports.foo = function(req, res){
res.render('foo', <テンプレートに与えるデータ>)
};
最後に「views/foo.jade」ファイルを作成、表示するHTMLに対応したテンプレートを作成する、といった流れとなる。
expressアプリケーションの設定と静的ファイルの配信
app.js内ではルーティングに加え、アプリケーションの環境設定も行われている。リスト5がその該当部分だ。
リスト5 app.js内のアプリケーション設定部分
app.configure(function(){
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
app.use(express.static(__dirname + '/public'));
});
まず「app.set('views', __dirname + '/views');」の行だが、これはテンプレートの格納ディレクトリを指定するものだ。ここでは「views」以下を指定している。次の「app.set('view engine', 'jade');」行はテンプレートエンジンを指定するもので、ここではJadeを使用するよう設定している。これらの設定を変更することで、テンプレートを格納するディレクトリを変更したり、Jade以外のテンプレートエンジンを利用することができる。
続く「app.use()」行では、「Middleware」と呼ばれるexpressの拡張モジュールを登録している。expressではMiddlewareを用いてその動作を拡張・カスタマイズできるようになっており、デフォルトではPOSTで送信されたデータを自動的にパースするexpress.bodyParserモジュールと、HTTPメソッドのオーバーライドに対応するexpress.methodOverrideモジュールを利用するよう設定されている。
「app.use(app.router)」は、先に説明したルーティング機構を有効にするよう設定している部分だ。最後の「app.use(express.static(__dirname + '/public'));」では、静的なファイルの配信を可能にするexpress.staticモジュールの追加と設定を行っている。引数に指定したディレクトリが静的に配信するファイルを格納するディレクトリとなり、ここでは「public」ディレクトリ以下を静的コンテンツの格納ディレクトリに指定している。この例では、たとえば「http://<ホスト名>/stylesheets/style.css」というファイルをリクエストした場合、/public/stylesheets/style.cssファイルが返されるようになる。
expressで採用されているテンプレート「Jade」
expressでは、「Jade」というテンプレートエンジンが採用されている。Jadeフォーマットのテンプレートは、HTML要素のネスト構造をインデントで表現するのが特徴だ。詳しくはJadeのドキュメントを参照してほしいが、たとえばスケルトンに記述されているリスト6のコードに対し、「{ title: 'Express' }」というデータを与えてレンダリングを行うと、リスト7のようなHTMLが生成される。
リスト6 Jadeのソースコード例
!!!
html
head
title= title
link(rel='stylesheet', href='/stylesheets/style.css')
body
h1= title
p Welcome to #{title}
リスト7 生成されるHTML
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title>Express</title>
<link rel="stylesheet" href="/stylesheets/style.css"/>
</head>
<body>
<h1>Express</h1>
<p>Welcome to Express</p>
</body>
</html>
JadeではそれぞれのHTML要素を「<」や「>」を付けずに記述し、その直後から改行までのテキストがその要素に含まれる内容となる。また、改行に続いてインデントが行われた場合、そのインデントレベルが終了するまでがその要素の内容となる。要素に与える属性は要素名に続いて()を付け、その中で「<属性名>=<値>」という形で指定する。