Help us understand the problem. What is going on with this article?

express-generatorで生成したapp.js のコードを1行ずつ解読

More than 1 year has passed since last update.

express-generatorで生成したテンプレートのapp.jsのコードを日本語訳する。

コードの意味を解説している記事や公式ドキュメントを参照しながら、できる限り噛み砕いてクドイ言い回しで解釈していく。

勉強中の関連記事まとめ
自分用の勉強記事をまとめた目次 ~擬似知識体系~

勉強に必要な準備

使用するPCに以下のパッケージがインストールされているものとする。

  • npm
  • Node.js
  • Express.js
  • express-generator

勉強に使ったExpressのバージョン確認

$ express --version
4.16.1

テンプレートファイルの生成

$ express myapp

生成されたテンプレートのapp.jsの中身

app.js
 1 var createError = require('http-errors');
 2 var express = require('express');
 3 var path = require('path');
 4 var cookieParser = require('cookie-parser');
 5 var logger = require('morgan');
 6
 7 var indexRouter = require('./routes/index');
 8 var usersRouter = require('./routes/users');
 9
10 var app = express();
11
12 // view engine setup
13 app.set('views', path.join(__dirname, 'views'));
14 app.set('view engine', 'jade');
15
16 app.use(logger('dev'));
17 app.use(express.json());
18 app.use(express.urlencoded({ extended: false }));
19 app.use(cookieParser());
20 app.use(express.static(path.join(__dirname, 'public')));
21
22 app.use('/', indexRouter);
23 app.use('/users', usersRouter);
24
25 // catch 404 and forward to error handler
26 app.use(function(req, res, next) {
27   next(createError(404));
28 });
29
30 // error handler
31 app.use(function(err, req, res, next) {
32   // set locals, only providing error in development
33   res.locals.message = err.message;
34   res.locals.error = req.app.get('env') === 'development' ? err : {};
35
36   // render the error page
37  res.status(err.status || 500);
38   res.render('error');
39 });
40
41 module.exports = app;

require部分(1~10行)

1行目

 1 var createError = require('http-errors');

1行目のvar createError = require('http-errors');は、npmレジストリから入手できるNode.jsモジュールのhttp-errorsapp.jsに読み込んでいる。createErrorという変数にhttp-errorsモジュールをrequire()で読み込んで格納している。http-errorモジュールによって404などのhttpエラーを簡単に作成できる。

ここで読み込んでいるhttp-errorモジュールはいつのまに用意されていたのかと言うと、express-generatorでテンプレート生成したときにまとめて用意されている。

参考文献
http-errors (公式ドキュメント)

require()で読み込むファイルパスが省略されてモジュール名だけで済んでいるのは、require()の仕組みとして検索優先度があってnode_module/は優先度が高い検索領域だからパスを記述しなくても見つけてくれる。

参考文献
Node.jsのrequireの検索パス

2行目

 2 var express = require('express');

2行目のvar express = require('express');は、node_module/にあるexpressモジュールを読み込んで変数expressに格納している。expressモジュールはexpress-generatorのテンプレートに最初から含まれている。

expressモジュールとは、Node.jsでMVCを容易に実現するのに必要なコードが書かれたフレームワーク。

参考文献
Node.js モジュール追加(Express)
MVC とは何かを 1 から学ぶ

3行目

 3 var path = require('path');

3行目のvar path = require('path');は、Node.jsの標準モジュールの一つであるpathモジュールを読み込んでいる。

pathモジュールとは、ファイルパスの文字列の解析や操作などの機能を提供してくれる。よく分からないが例えばpath.resolveという関数だと絶対パスに変換するなど。

参考文献
Node.js API (path) - ファイルパスの文字列操作
webpack.config.jsで思ったpath.resolveって何のためにあるの?

4行目

 4 var cookieParser = require('cookie-parser');

4行目のvar cookieParser = require('cookie-parser');は、cookie-parserモジュールを読み込んでいる。

cookie-parserモジュールとは、req.cookies関数によってcookieヘッダーを解析してcookie名をキーとするオブジェクトを生成するもの。

参考文献
cookie-parser (公式ドキュメント)

5行目

 5 var logger = require('morgan');

morganモジュールを読み込んでいる。morganモジュールとは、簡単にログ出力をするためのもの。

参考文献
morgan (公式ドキュメント)
Express4のログ出力(morgan)について

7行目

 7 var indexRouter = require('./routes/index');

routes/index.jsを読み込んで、そこに書かれているコードを変数indexRouterに格納している。routes/ディレクトリに保存されるjsファイルはクライアントのリクエストに対するレスポンスが書かれている。その内容を格納する変数名はファイル名Routerとするのが作法っぽい。そしてroutex/ディレクトリにファイルを作成するたびにapp.jsのこの部分で列挙して読み込んでおくらしい。

8行目

 8 var usersRouter = require('./routes/users');

7行目と同じくroutes/users.jsファイルを読み込んでいる。express-generatorで生成したテンプレートは初期状態でindex.jsusers.jsが作成されている。今後アプリをコーディングしていく過程で独自のファイルを追加していくものと思われる。

10行目

10 var app = express();

2行目でexpressモジュールを変数expressに読み込んでおいたものをexpress()で実行し、そのときに生成されたコード群を変数appに格納している。今後はappという変数からプロパティアクセスする(app.get()など)ことで様々な変数やメソッドを呼び出すことができるようになった。メソッドの一覧は公式ドキュメントを参照。

簡単な言い回しに直しておくと、var express = require('express');は「モジュールの読み込み」と言い、var app = express();は「オブジェクトの作成」と言うと分かりやすい。

参考文献
【Node.js入門】初心者のためのExpress入門(GET / POST)
express() - 4.x API(公式ドキュメント)

view engine setup部分(12~23行)

13行目

12 // view engine setup
13 app.set('views', path.join(__dirname, 'views'));

app.set()はアプリケーションに必要な各種設定情報をセットするオブジェクトとメソッドの組み合わせ。ここではviewディレクトリのパスをセットしている。

表示されるView Engineがどこのフォルダに入っているのかを設定。

※まだ具体的な構文の意味を理解できていない。

参考文献
app.set(名前、値) - 4.x API(公式ドキュメント)
はじめてのExpress.js 〜導入編(2)〜
Expressオブジェクト app.set()の意味が分からないときに確認する方法
node.jsでejsというview engineを使ってみる

14行目

14 app.set('view engine', 'jade');

テンプレートエンジンのjadeを使えるように設定。jadeモジュールはnode_modules/の中に標準インストールされている。

どのview engineを使うのかを設定

ここに表記されているテンプレートエンジンはExpressテンプレートファイルを生成する際にexpress myapp --view=ejsのようにオプションで変更できる。デフォルトではjadeになる。変更した場合はviews/の中に生成されるファイルの拡張子も.ejs.jadeに書き換わっている。

※まだ具体的な構文の意味を理解できていない。

参考文献
はじめてのExpress.js 〜導入編(2)〜
Expressオブジェクト app.set()の意味が分からないときに確認する方法
node.jsでejsというview engineを使ってみる

app.useでいろいろ設定

16行目

16 app.use(logger('dev'));

logger()はログを出力するミドルウェア。引数の'dev'は出力フォーマットの指定らしい。

ここでのapp.use()は、アプリでlogger('dev')を使うという処理だと思う。デバッグ用のコードと思われる。

参考文献
Express loggerの使い方
API: dev プロパティ - Nuxt.js公式ドキュメント

17行目

17 app.use(express.json());

express.json()メソッドは、Body-Parserを基にした機能で、クライアントから送信されたデータをreq.body経由で取得して操作する。

要は、何かjsonに関するデータを取得して解析して処理をするコードということ。

参考文献
express.json([options]) - 4.x API(公式ドキュメント)
Body-ParserがExpressにexpress.json()として標準搭載されている話

18行目

18 app.use(express.urlencoded({ extended: false }));

URLエンコードとは、URLで使用出来ない文字の変換を行うプロセス。express.urlencoded()メソッドはそんな感じの処理をうまくやってくれるやつ。extended: falseだから拡張せずデフォルトで運用するという意味と思われる。

参考文献
express.urlencoded(オプション) - 4.x API(公式ドキュメント)

19行目

19 app.use(cookieParser());

cookieParser()req.cookiesCookieヘッダーを解析してCookie名をキーとするオブジェクトを入力するメソッド。

参考文献
cookie-parser - GitHub

20行目

20 app.use(express.static(path.join(__dirname, 'public')));

express.static()serve-staticに基づいて静的ファイルを提供するミドルウェア。

public/に入っているのはcssやjsやimgなどの静的ファイルで、それを参照して読み込むための処理なんだと思う。

参考文献
express.static(root、[オプション]) - 4.x API(公式ドキュメント)

22行目

22 app.use('/', indexRouter);

app.use()とは、アプリケーションにミドルウェアをバインドするためのもの。app.use('マウントパス', ミドルウェア);で要求されたパスのみにミドルウェアを適用されるように制限されている。22行目のコードでは、'/'すなわちトップページに対して変数indexRouterに格納しておいたミドルウェアを適用するという内容になっている'/'でアクセスしてきたらindexRouterの中身を実行する。

パスの'/'すなわちhttp://domain/getで受け取った際に変数indexRouterに格納しておいたroutes/index.jsのコードを実行する。

つまりapp.jsのこの部分には、アクセスしたパス'/'に対応するテンプレートファイルroutes/index.jsに記述された変数名.get()によってres.render()のプロパティ値をviews/index.jadeに渡すことでアプリ画面をレンダリングする、という処理が書かれている。

下記はroutes/index.jsに書かれたget()の部分。app.get()は要求されたときに特定のルートを照合して処理するためのもの。

index.js
indexRouter.get('/', function(req, res, next){
  res.render('index', {title: 'Express'});
});

そして下記がviews/index.jadeに書かれたプロパティ値を受け取ってレンダリングする位置の抜粋。プロパティ名の#{title}がプロパティ値の'Express'に置換される。

index.jade
  p Welcome to #{title}

この場合<p>タグで「Welcome to Express」とレンダリングされることになる。

参考文献
はじめてのNode.js 2
node.js – express.jsのapp.useとapp.getの違い

23行目

23 app.use('/users', usersRouter);

処理の内容は22行目と同じ。

パスの'/users'すなわちhttp://domain/users/getで受け取った際に変数usersRouterに格納しておいたroutes/users.jsのコードを実行する。

catch 404 and forward to error handler部分(25~28行)

26行目

25 // catch 404 and forward to error handler
26 app.use(function(req, res, next) {
27   
28 });

メソッドの引数として無名関数を渡し、その関数の処理結果をapp.useするというもの。具体的な処理は27行目の方で説明する。

function(req, res, next)の引数の順番は入れ替え可能だが、慣習どおりこの順番で書いておくのが無難。第三引数のnextは何やら処理を終了させず継続させるための云々というものらしい。

参考文献
nodejs express の next()って結局なんですか?

27行目

27   next(createError(404));

next(セレクタ)とは、対象要素の次に配置されている要素だけを取得するメソッド。セレクタとは、next()メソッドで取得する合致条件のようなもので、ここのコードではセレクタとしてcreateError(404)が指定されている。これは404エラーでメッセージを生成するということ。

つまり26~27行目のコードは、「404エラーが返された際の次の処理を取得するという処理をapp.use()する」ということ。

参考文献
【jQuery入門】next(),nextAll(),siblings()で兄弟要素を取得する!
http-errors - npm公式ドキュメント

error handler部分(30~39行)

エラー関連の細かい処理らしいが、ちょっと今のレベルではよく分からん。後回し。

参考文献
エラー処理/デフォルトのエラー処理 - 4.x API(公式ドキュメント)

31行目

30 // error handler
31 app.use(function(err, req, res, next) {
     
39 });

33行目

32   // set locals, only providing error in development
33   res.locals.message = err.message;

34行目

34   res.locals.error = req.app.get('env') === 'development' ? err : {};

37行目

36   // render the error page
37   res.status(err.status || 500);

38行目

38   res.render('error');

エラーをレンダリングする処理。

exports部分(41行目)

41行目

41 module.exports = app;

exportsは、指定した値をモジュール化して外部ファイルから読み込めるようにできる。そしてモジュール化したコードを他のファイルからrequireで読み込むことになる。exportsmodule.exportsの違いは参考文献を参照。

このようにNode.jsでは、モジュール化してさまざまな機能を持つプログラムを個別のファイルに分割し、効率的にコードを管理したり、プログラムを再利用しやすくする。Node.jsにおいて、全てのjsファイルの最後の行でmodule.exportsしているのはそういうこと。

ここのコードの処理を解読する。これまでapp.jsのコードの10行目でexpress()を読み込み、その他いろいろとapp.set()やらapp.use()やらで開発中のアプリケーションの機能を設定してきた。そうしたコード群を改めてモジュール化して外部ファイルと連帯させるために、コードの最後で変数appmodule.exportsしている。

参考文献
【Node.js入門】exports / module.exportsによるモジュール機能の使い方まとめ!

app.js全体を日本語訳してみる

当初の目的であったapp.js全体のコードの解読を行う。できるかぎりわかりやすくするため、まずは日本語に置き換える実験をしてみる。

app.js
 1 var createError = require('http-errors');
 2 var express = require('express');
 3 var path = require('path');
 4 var cookieParser = require('cookie-parser');
 5 var logger = require('morgan');
 6
 7 var indexRouter = require('./routes/index');
 8 var usersRouter = require('./routes/users');
 9
10 var app = express();
11
12 // view engine setup
13 app.set('views', path.join(__dirname, 'views'));
14 app.set('view engine', 'jade');
15
16 app.use(logger('dev'));
17 app.use(express.json());
18 app.use(express.urlencoded({ extended: false }));
19 app.use(cookieParser());
20 app.use(express.static(path.join(__dirname, 'public')));
21
22 app.use('/', indexRouter);
23 app.use('/users', usersRouter);
24
25 // catch 404 and forward to error handler
26 app.use(function(req, res, next) {
27   next(createError(404));
28 });
29
30 // error handler
31 app.use(function(err, req, res, next) {
32   // set locals, only providing error in development
33   res.locals.message = err.message;
34   res.locals.error = req.app.get('env') === 'development' ? err : {};
35
36   // render the error page
37  res.status(err.status || 500);
38   res.render('error');
39 });
40
41 module.exports = app;

app.jsを日本語訳にすると、

アップ.js
 1 サーバー接続やエラーに関するモジュールを読み込む
 2 フレームワークに関するモジュールを読み込む
 3 パス管理に関するモジュールを読み込む
 4 クッキーに関するモジュールを読み込む
 5 ログ出力に関するモジュールを読み込む
 6
 7 トップページの内容を取得しておく
 8 ユーザページの内容を取得しておく
 9
10 'express()'モジュールの処理結果を'app'に入れとく
11
12 // 描画エンジンの設定
13 テンプレートファイルが'views/'に入ってることを把握
14 テンプレートエンジンは'jade'に設定
15
16 ログ出力のフォーマットは'dev'を使う
17 jsonファイルを解析するメソッドを使う
18 URLエンコード方式は拡張せずに使う
19 クッキーを解析するメソッドを使う
20 静的ファイルが'public/'に入っていることを把握
21
22 トップページにアクセスしたときは'index.js'を表示
23 ユーザページにアクセスしたときは'users.js'を表示
24
25 // 404エラーだったらエラー表示する処理
26 
27   404エラーが出たらとりあえず次の処理に移行
28 
29
30 // エラー表示する機能について
31 
32   // ローカルにおいて開発者にだけエラー表示する処理
33   res.locals.message = err.message;
34   res.locals.error = req.app.get('env') === 'development' ? err : {};
35
36   // エラーページの表示処理
37  'err.status'の中身のいずれかが500エラーだったら
38   以上のエラー内容を画面に表示
39 
40
41 ここまでのコードをモジュール化して使いやすくする

とりあえずExpressで入門用アプリを作るにあたって、

 7 var indexRouter = require('./routes/index');

の部分のように複数のページを追加して読み込み、routes/~.jsviews/~.jsonファイルなども作成して、静的なHPを作ってみるといいかも。

アプリ開発する際に、こんな感じでコードの意味を解釈しながら書けたらいい。もっと深い意味もわかるように情報収集せねば。

その他メモ

もしかしたら補足勉強で必要になりそうな参考文献をメモしとく。

参考文献
node初心者がexpress-generatorで吐き出されたapp.jsを読んでみる
body-parser
express実践入門

oekaki-hoho-ron
理屈で絵が描けることを証明する「お絵描きホーホー論」
https://note.mu/oekaki_hoho_ron
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away