Expressのテンプレートエンジンにejsを使う時、ejs内でexpressのlocalsを参照できる


はじめに

Expressでテンプレートエンジンejsを使った実装をする時に、ejs内ではExpressのlocalsを参照できるという事を知ったので、具体的にどうなるのか?を少しまとめてみた。

ejs内ではexpressのapp.localsやres.localsのlocalsを参照できる

res.render(view [, locals] [, callback])には、

locals, an object whose properties define local variables for the view(ビューのローカル変数を定義するプロパティを持つオブジェクト).

と書かれているので、あくまでres.render()の第二引数に渡す値のみがテンプレートエンジン内(ejs)で使えるのかと思っていたが、実際にはejs内ではlocalsというオブジェクトに、res.render()の第二引数のオブジェクトと、expressのlocals(app.localsやres.localsのlocals)に定義済みのオブジェクトが全て組み込まれており、それらがすべて使える。

実際に、以下のようなソースを書いてみた時にの画面の描画内容からもこの事は確認できた。

<body>
  ...
  <% for (let local of Object.keys(locals)) { %>
    <li><%= local %></li>
  <% } %>
  ...
</body>

↑ は、以下の実装において、app.locals.poolapp.locals.fsSqlres.locals.momentres.locals.paddingという設定をしていることにより、locals内にpoolfsSqlmomentpaddingなどが存在している。また、その他のidnameなどは、SQLの戻り値として返ってきたもので、res.render()の第二引数に渡しているので存在している。

paddingは関数であるが、これはexpressのres.localsには変数(値)だけでなく、オブジェクトや関数を渡す事もできるので、ejs内でlocals内に定義した関数を呼び出す事も可能。関数をejs内で呼び出す例としては、ここを参照。また、関数をres.localsに定義している部分は、ここを参照(localsを明示的に書いているが、省略してpaddingとする事も可能)。

client.js#L7
// https://github.com/yuta-katayama-23/post-restaurant-reviews/blob/657bfebd338886c532a32f80b65146543de75623/src/lib/database/client.js#L7
app.locals.pool = pool;
app.locals.fsSql = new SqlQueryLoader({
    path: 'src/lib/database/sqls'
});
app.js#L22
// https://github.com/yuta-katayama-23/post-restaurant-reviews/blob/657bfebd338886c532a32f80b65146543de75623/src/app.js#L22
app.use((req, res, next) => {
    res.locals.moment = moment;
    res.locals.padding = padding;
    next();
});
shops.js#L14
// https://github.com/yuta-katayama-23/post-restaurant-reviews/blob/657bfebd338886c532a32f80b65146543de75623/src/routes/shops.js#L14
try {
    const [rows] = await pool.query(
        fsSql.readSync('tran_shops', 'SELECT_SHOP_DETAIL_BY_ID'),
        [id]
    );
    res.render('./shops/index.ejs', rows.shift());
} catch (err) {
    next(err);
}

※ソースコードの全体は以下。

※expressのapp.localsについては、app.localsを参照。

参考文献