at backyard

Color my life with the chaos of trouble.

Expressのappモジュールを元にして簡単にSitemapを生成するためのnpmパッケージ【easy-express-sitemap-generator】を作成した

作ってみた報告です(まだAlpha版ですが)。

Expressのappモジュールを元にして簡単にSitemapを生成するためのnpmパッケージを作りました。

名前はeasy-express-sitemap-generatorといいます。

github.com

インストールする際は

npm install easy-express-sitemap-generator
# または
yarn add easy-express-sitemap-generator

で行えます。

目次

作成した動機

Expressのappモジュール内にはルーティングに関する情報が格納されていると思いますが、その情報を元にサイトマップを生成する仕組みのようなものが(自分が探してみた限りでは)なさそうだったので、作りました。

使い方

expressのappモジュールを利用するため、ユーザ側がサイトマップを生成する処理を書く必要はありません。

例えば下記のような処理でapp内で設定したルーティング情報を元にサイトマップを生成することが可能です。

const express = require('express');
const app = express();
const generateSitemap = require('easy-express-sitemap-generator');

app.get('/', (req, res) => {
  res.send('path: "https://example.com/"');
});

app.get('/about', (req, res) => {
  res.send('path: "https://example.com/about"');
});

const YOUR_SITE_URL = 'http://example.com';

const sitemap = generateSitemap(app, YOUR_SITE_URL);

console.log(sitemap);

これを実行すると、下記のようなサイトマップがコンソール上に出力されます。

<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <url>
    <loc>
      http://example.com/
    </loc>
  </url>
  <url>
    <loc>
      http://example.com/about
    </loc>
  </url>
</urlset>

もちろん、オプションとして除外するURLも指定できるので、生成するURLはこちらである程度制御できます。

逆にサイトマップ自体の書き方については今のところオプションなどは用意していません。

これはもし要望が出てくるようなことがあれば将来的に実装していこうと思います。

内部の仕組み

内部の処理については実際にExpressのappモジュール内を覗きつつ、愚直に処理を実装しています。

コード自体は洗練されていません。ここらへんは一旦希望する動作を実現させることを優先しています。

そのためこういう処理の書き方が良いのか、というのはなんとも言えません。が、Express内部の処理構造に変更がない限りは問題なく動くと思います。

ここでは、実際に書かれているコード( v0.0.3 )を元にExpressのappモジュールからルーティング情報を取得するための方法を備忘録がてら書いて以降来ます。

Expressでルーティング情報を取得する方法(1つ目)

Expressでは2種類の方法でルーティング情報を設定することが可能です。

1つ目は下記のように行う方法。

const express = require('express');
const app = express();

app.get('/', (req, res) => {
  res.send('path: "/"');
});

app.get('/about', (req, res) => {
  res.send('path: "/about"');
});

module.exports = app;

Expressでは、エクスポートした app モジュールの中を見てみると、設定されたルーティング情報は下記のリストに格納されています。

app._router.stack # stackという配列の中に他の要素と入り混じってルーティング情報が格納されています。

この stackそれぞれの要素の中には name という属性があり、 例えば app._router.stack[0].name で参照したときに、格納されている情報に関する文字列がここには格納されています。

上記方法で設定した場合に app._router.stack[0].name には bound dispatch という文字列が格納されています。

そして bound dispatch という名前を持ったオブジェクトの中には、app._router.stack[0].route の中に格納されたルーティング用のパスが格納されています。

文字にすると、いささか冗長な説明になってし合いますが、 easy-express-sitemap-generator内のテストコードを見れば、より分かるかと思います。
(コードは汚いですが...)

Expressでルーティング情報を取得する方法(2つ目)

Expressでは上記方法とは別に、routing用のモジュールを別途作成してそちらを読み込んで使用することも可能です。
(こちらのほうが利用されるケースとしては多いかと思います)

例えば下記のようにルーティング情報のみを記載したファイルを作成します。

const express = require('express');
const router = express.Router();

router.get('/', (req, res) => {
  res.send('path: "https://example.com/"');
});

router.get('/about', (req, res) => {
  res.send('path: "https://example.com/about"');
});

module.exports = router;

そして、これを app.js 側で読み込みます。

const express = require('express');
const app = express();
const indexRouter = require('./routes/index');

app.use('/', indexRouter);

module.exports = app;

このようにしてルーティング情報を設定した場合、上で説明したのと同様に下記にルーティング情報は格納されていますが、

app._router.stack # stackという配列の中に他の要素と入り混じってルーティング情報が格納されています。

app._router.stack[0].name内の文字列が router という名前になります。

さらには下記の中にエクスポートされたルーティング情報の配列が格納されています。

app._router.stack[0].handle.stack # ルーティング情報の配列

stackには入れ子のようにしてルーティング情報に関する配列が格納されているので、さらにこの中を覗いていくようになります。

app._router.stack[0].handle.stack[0].route.path # ルーティングパスがここにある

最後に

以上のようなことを調べながら、これらのパスを取り出してサイトマップを生成するような処理を easy-express-sitemap-generator では行っています。

これがExpressにおけるサイトマップ生成の最適解かどうかは分かりませんが、ずっとExpressのappモジュールを読み込ませるだけでサイトマップ用の文字列を生成できる仕組みは欲しかったので、一応のところは実現できて満足しています。

まだまだ見直すべき箇所はありますが、ひとまず形にできたので、ここまでの経緯をブログに残すことにしました。

PRなどもウェルカムなので、気になる箇所などあればPRください。

余談(日記)

昨日、フジロックの配信を時折覗いていましたが、夜に見たナンバーガールはやはりかっこよかったです。

途中で子供を寝かしつけるために音量を下げ、うすく演奏を流しながら子供を寝かしつけていましたが、ささくれだったサウンドながら薄い音量で流していると睡眠導入にも効果があるのだなと思いました。
(すぐ私も子供も眠りに落ちた)

あと、ナンバーガールを聴きながら子供も楽しそうに踊っていて、子供受けも良いなと思いました。

そんな夏の終りの夜でした。