Express Generator で作成されたファイルを触って Express を理解したい2：router, pug

# 主旨

Experss 4.x が対象です。`express app_name --view=pug` として生成されたファイルを見ながら、`express` の仕組みを理解していく。

- この時事は、この記事の続きです。前回の記事では、`yarn start` コマンドと `package.json` との関係、static ファイルと `public` フォルダの関係、`app.use()` の評価される順序、`path.join` と `__dirname` について記述している。

この記事では、`router` (`./routes` 以下の `.js` ファイル) と `views` 以下にある `.pug` について記述している。

## 前提

以下の記事は、`express-generator` を使って下記のコマンドで `app.js` 以下のファイルを生成していると想定している。

```
$ express appname --view=pug
```

生成されたファイルは以下の通り。

```
project_dir
├── app.js          # アプリのメインファイル
├── bin
│   └── www            # yarn start 時に node bin/www として実行されるファイル
├── package.json       # ライブラリ等の依存関係やバージョン情報を格納したファイル
├── public          # static なファイルを置くフォルダ
│   ├── images         # http://localhost:8000/images 
│   ├── javascripts    # http://localhost:8000/javascripts 
│   └── stylesheets    # http://localhost:8000/stylesheets
│       └── style.css  # http://localhost:8000/stylesheets/style.css
├── routes          # router (ミドルウェア) 置き場
│   ├── index.js       # http://localhost:8000/ (トップページ)
│   └── users.js       # http://localhost:8000/users
└── views           # テンプレートファイル置き場
    ├── error.pug      # エラー時のテンプレート
    ├── index.pug      # index.js 用のテンプレート
    └── layout.pug     # index.pug や error.pug に読みこまれるテンプレート
```

実行時には 8000 番ポートを指定して使うものとする。

```
$ PORT=8000 yarn start
```

実行後、ブラウザで `http://localhost:8000` にアクセスしたときに、下記の表示になっているものとする。

<img src="https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F266247%2F8389c9ab-7a60-9055-def6-ccf760c1c19d.png?ixlib=rb-1.2.2&auto=format&gif-q=60&q=75&s=f25aa30c763746f5bfcaccc475857e38" width="60%"/>

## routes/index.js と app.js の関係

`routes/index.js` は生成時は以下のような内容になっている。

```routes/index.js
var express = require('express');
var router = express.Router();

/* GET home page. */
router.get('/', function(req, res, next) {
  res.render('index', { title: 'Express' });
});

module.exports = router;
```

`index.js` は `app.js` の下記の記述によって呼び出される。

```app.js
var indexRouter = require('./routes/index');

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

上の `require` の行で `index.js` を `app.js` に読みこみ、下の行 (`app.use()` で http://localhost:8000/ にアクセスがあったときに、`index.js` を実行するようにしている。いずれの行が欠けても、プログラムは正常に動作しない。

試しに `app.use('/', indexRouter);` をコメントアウトして `PORT=8000 yarn start` を実行し、http://localhost:8000/ にアクセスすると、

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/a939a7de-0386-64fa-b746-aede10e7a790.png" width="60%"/>

このように、Express ページは表示されなくなる。

`require` 側を消すと、`indexRouter` が未定義となって、アプリの実行自体がエラーになる。

```
$ PORT=8000 yarn start
/Users/hoge/Documents/github/express_sample/app.js:22
app.use('/', indexRouter);
             ^

ReferenceError: indexRouter is not defined
```

## app.js と routes/index.js の関係

再び、app.js を下記の状態に戻してからスタート。

```app.js
var indexRouter = require('./routes/index');

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

今度は、`app.use` 側を以下のように変更してみる。

```app.js
app.use('/hoge', indexRouter);
```

これで `PORT=8000 yarn start` を実行し、http://localhost:8000/ にアクセスすると、

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/a939a7de-0386-64fa-b746-aede10e7a790.png" width="60%"/>

エラーになる。これは、サーバのルート `/` にマッチするパスの記述を消したから。かわりに、http://localhost:8000/hoge にはアクセスできる。

<img src="https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F266247%2F8389c9ab-7a60-9055-def6-ccf760c1c19d.png?ixlib=rb-1.2.2&auto=format&gif-q=60&q=75&s=f25aa30c763746f5bfcaccc475857e38" width="60%"/>

このように、`app.use` の一つ目の引数のパスを変更することで、`index.js` を表示するパスを変更できる。

ちなみに、下記のようにして複数のパスを `index.js` に紐付けることもできる。

```app.js
var indexRouter = require('./routes/index');

app.use('/', indexRouter);
app.use('/hoge', indexRouter);
app.use('/foo/bar', indexRouter);
```

それぞれ、下記の URL でアクセスできる。

- http://localhost:8000
- http://localhost:8000/hoge
- http://localhost:8000/foo/bar

このような、パスと実行ファイル (`index.js` ) を紐付けることを**ルーティング**と呼ぶ。`index.js` のような、`app.use` の二つ目の引数で呼びだされる外部モジュールや関数のことは**ミドルウェア**と呼ばれる。

このように、express-generator では、

- `app.js` にルートの記述をする (ルーティング)
- `routes` 以下に、ページを表示したり http クエストを処理するミドルウェアの `.js` ファイルを置く

という構成になるように、ファイルが生成される。あくまで、express-generator がデフォルトでこのような構成でファイルを生成するというだけで、このような構成でしか web アプリが記述できない、というわけではない。アプリの記述に慣れてきたら、ディレクトリやファイルの構成を都合のよいようにカスタマイズしても問題はない。

## routes/index.js と views/index.pug の関係

`index.js` の中身を見ていく。デフォルトでは下記のようになっている。

```routes/index.js
var express = require('express');
var router = express.Router();

/* GET home page. */
router.get('/', function(req, res, next) {
  res.render('index', { title: 'Express' });
});

module.exports = router;
```

ブラウザにアクセスしたときに表示される "Express" ページは、

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

この関数で生成されている。試しに `'Express'` の表記を `'超Lチカ'` に変更し、`PORT=8000 yarn start` しなおしてから http://localhost:8000 にアクセスすると、

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/f9a8a5d8-4374-811f-d168-e87b4c560ae8.png" width="60%"/>

このように、表示される文字が変更される。`res.render()` 関数の二つ目の引数で指定するオブジェクトの、`title:` のキーに対応する値によって、文字が変更されていることは分かる。しかし、`title` を変更することで、表示される文字の一部を変更することはできるが、ページのレイアウト自体を変更することはできない。ページのレイアウトを変更するためには、一つ目の引数を理解する必要がある。

一つ目の引数の `index` に対応するのは、`views/index.pug` ファイルである。`views/index.pug` ファイルの中身は以下のようになっている。

```views/index.pug
extends layout

block content
  h1= title
  p Welcome to #{title}
```

これは、HTML を簡略化した記法で書かれた「webページのテンプレート」で、pug というテンプレートエンジンによって、ページが読みこまれるときには HTML に変換されて、ブラウザに送信される。上記の記述を HTML に書き直すとすると、下記のようになる。

```.html
<!DOCTYPE html>
<html>
<head>
    <title>title</title>
    <link rel="stylesheet" href="/stylesheets/style.css">
</head>
<body>
    <h1>title</h1>
    <p>Welcome to #{title}</p>
</body>
</html>
<!DOCTYPE html>
```

見やすいようにインデントや改行を入れているけど、実際にテンプレートエンジンで生成される出力には改行やインデントはなされない。

元になっている pug ファイルは、おおむね下記のルールで HTML を簡略化して記述できる。

- ひとつのタグをひとつの行で書く
- タグの入れ子状態をインデントの深さで表わす
- タグのパラメータは括弧内に記述する (link(rel="stylesheets") のように)
- インデントの終わりが「タグ閉じ」に相当する

詳しい説明のある記事はいくつかあるので、そちらを参考にされたい。

- https://qiita.com/cotolier_risa/items/135d168eddd6ae6c3409
- https://uetani33.net/pug-howto/

これらに加えて、変数も使うことができる。上の例では、プログラムの実行時に `title` の部分に `res.render()` の二番目の引数で指定されたオブジェクトの `title:` の値が挿入される。`routes/index.js` の場合、`title:` の値は `Express` となっているので、`views/index.pug` と `routes/index.js` から生成される HTML ファイルは下記のようになる。

```.html
<!DOCTYPE html>
<html>
<head>
    <title>超Lチカ</title>
    <link rel="stylesheet" href="/stylesheets/style.css">
</head>
<body>
    <h1>超Lチカ</h1>
    <p>Welcome to 超Lチカ</p>
</body>
</html>
<!DOCTYPE html>
```

`views/index.pug` に含まれる `#{title}` という文字列は、`routes/index.js` で指定された `超Lチカ` という文字列に置き変わる。`.pug` ファイルに `#{name}` という形式の記述は pug においては name という変数であると解釈され、`res.render` の引数を使って、対応する変数に埋め込む文字列を変更できる。

試しに、`views/index.pug` と `routes/index.js` を下記のように書きかえてみると…

```views/index.pug
extends layout

block content
  h1= title
  p Welcome to #{world}
```

```routes/index.js
var express = require('express');
var router = express.Router();

/* GET home page. */
router.get('/', function(req, res, next) {
  res.render('index', { title: '超Lチカs', world: "the World!" });
});

module.exports = router;
```

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/f0e5f96d-f4c5-777e-f4d8-20c2a0b4ac0e.png" width="60%"/>

こうなる。

また、`index.pug` 内にある `h1` や `p` といったタグの直後に `=` を書くと、その直後にある文字列は `#{}` が付いている変数であると解釈される。たとえば、上の例では、`title=` のタグに `=` が付いているので、直後にある `title` という文字列は変数として扱われ、`title= title` という記述は `title 超Lチカ` という記述に置きかわる。

変数名に普通の単語を使うと、ただの文字列なのか変数なのか分かりにくくなってバグが起きやすい。たとえば、変数名にはアンダースコアを使って `_title` のように記述するとか、すべての変数は常に `#{title}` のように `#{}` 付きで表記するというようなルールを決めて、文字列との区別が容易なようにしておくと、想定外のバグを防ぎやすい。

## views/index.pug と views/layout.pug の関係

先に示したように、`views/index.pug` と `routes/index.js` から生成されるファイルには、あきらかに `views/index.pug` に含まれない記述がある。

```.html
<!DOCTYPE html> 
<!-- ここから -->
<html>
<head>
    <title>超Lチカ</title>
    <link rel="stylesheet" href="/stylesheets/style.css">
</head>         
<!-- ここからまでは index.pug には無い -->
<body>
    <h1>超Lチカ</h1>
    <p>Welcome to 超Lチカ</p>
</body>
</html>         <!-- ここと -->
<!DOCTYPE html> <!-- ここも index.pug には無い部分 -->
```

`index.pug` に無い部分は、`views/layout.pug` から読みこまれている。

```views/layout.pug
doctype html
html
  head
    title= title
    link(rel='stylesheet', href='/stylesheets/style.css')
  body
    block content
```

```views/index.pug
extends layout

block content
  h1= title
  p Welcome to #{title}
```

`views/index.pug` の冒頭にある `extends layout` という記述によって、`views/layout.pug` の内容を `views/index.pug` に読み込む指示をしている。これによって、`views/index.pug` は下記のように記述されてるかのように扱われる。

```views/layout.pug
doctype html
html
  head
    title= title
    link(rel='stylesheet', href='/stylesheets/style.css')
  body
    block content
      h1= title
      p Welcome to #{title}
```

block の展開のされ方はやや複雑で、次のルールで extends で読みこんだ側のファイル内に展開される。

- 読み込み先に同名の block が存在しない場合は、そのまま読み込まれ。
- 読み込み先に同名の block が存在する場合は、読み込み先の block の記述で上書きされる。

たとえば、`views/index.pug` と `views/layout.pug` が下記の状態だとする。

```views/layout.pug
doctype html
html
  head
    block scripts
      script src="hoge.js"
  body
    block main
      h1 ただのLチカ
```

```views/index.pug
extends layout

block main
  h1 超Lチカ
```

`views/index.pug` の冒頭に `extends layout` という記述があるので、まず `views/layout.pug` が読みこまれて、出力されるファイルのベースは下記のようになる。

```
doctype html
html
  head
    block scripts
      script src="hoge.js"
  body
    block main
      h1 ただのLチカ
```

次に `views/layout.pug` の中から、`views/index.pug` に書かれている `block main` と同名の `block` があるかを探す。この例の場合、`block main` が存在しているので、`views/index.pug`側にある `block main` の記述で、出力ファイルの中にある `block main` の記述を置きかえる。

```
doctype html
html
  head
    block scripts
      script src="hoge.js"
  body
    block main
      h1 超Lチカ
```

結果的に `h1 ただのLチカ` が `h1 超Lチカ` に置きかえられる。`block scripts` は `views/index.pug` に存在しないのでそのまま残る。

このように、block と extends の記述を使うことで、「テンプレートのテンプレート」のようなものを作ることができる。

## 余談: include を使って pug ファイルを読み込む

pug ファイルから別のファイルを読み込む方法として、extends の他に include という記述がある。

```views/index.pug
doctype html
html
  head
    include scripts
  body
    block main
      h1 ただのLチカ
```

```views/footer.pug
script src="hoge.js"
```

`include` でファイル名を指定すると、その場所にファイルの内容がそのまま読みこまれる。上の例の場合は、出力は下記になる。

```
doctype html
html
  head
    script src="hoge.js"
  body
    block main
      h1 ただのLチカ
```

extends とは違って、単純にファイルを読み込むだけ。include を使うことで、大きな pug ファイルを分割して管理することができる、

この他、if 文を使った条件分岐や、for 文を使ったループなども書ける。また pug ファイル内で変数を使うこともできる。詳しくは下記が参考になる。

- https://uetani33.net/pug-howto/#toc_id_5_1
- https://du-masa.github.io/study-frontend/pug/pug-lang.html

## 余談: 標準ミドルウェアとサードパーティミドルウェア

`app.js` の先頭のほうにある `app.use` 群も、ミドルウェアを使うためのコードになっている。

```.js
var cookieParser = require('cookie-parser');
var logger = require('morgan');

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` はパスの指定がない。パスの指定がない場合は、「あらゆるアクセス(リクエスト)に対して実行する」ものと解釈される、つまりこれらのミドルウェアは、すべてのアクセスに対して自動的に適用される。ただし各ミドルウェアは、パスがマッチしていても、それが「適用される条件を満たしているときにのみ」実行されるように実装されている。

たとえば、`expres.static` の記述は、 `./public` 以下にあるファイル名と同じファイル名(パス)が、`/` 直下に指定されていた場合にのみ実行される。ファイル名に対応するファイルが存在するときは、`./public` 以下にあるファイルの内容をそのままブラウザに返す。`./public` 以下に該当するファイルがない場合は、何も処理をせずに次の行の処理をする。

- [Express での静的ファイルの提供](https://expressjs.com/ja/starter/static-files.html)

また `logger` (morgan) のミドルウェアは、サーバのいずれのパスへのアクセスに対しても機能し、アクセスされたパス名、レスポンスコード、処理に要した時間などを、console に表示する(例えば下記のように)。

```
GET / 200 23.091 ms - 195
GET /stylesheets/style.css 304 0.427 ms - -
GET /users 304 0.809 ms - -
```

- [Express4のログ出力(morgan)について](https://qiita.com/mt_middle/items/543f83393c357ad3ab12)

`express.xxx` のようにして使うことができるミドルウェアは「標準ミドルウェア」と呼ばれ、`require` で読みこんで使用するミドルウェアは「サードパーティミドルウェア」と呼ばれる。サードパーティのミドルウェアについては、`require` 行を記述した後に `yarn install` することで、`node_module` ディレクトリ以下にインストールされ、プログラム中で使えるようになる。