Node.js+Express+EJSとWordPress REST APIでViewを再構築する実験

Node.js+Express+EJS
少し前に「WordPress 4.7のREST APIを使った記事閲覧プログラム」を掲載したが、これはクライアント側(ブラウザ)のみでの実験。今度はサーバー側にNode.jsを使ってBLOGのViewを再構築することに…。

これまでNode.jsはメッセージング系で少し触ったことがあるものの、Webサーバー、つまりApacheの替わりとしては使ったことがなかったので、WordPress 4.7のREST APIがある程度分かったついでに実験したくなった(笑)。

但し、管理画面も実装するならともかく、Viewだけだとクライアント側のみで出来るので、わざわざサーバー側でやることもなく、あくまでも遊びだ。

全体の概要

Node.jsの開発環境はググるといろいろ出てくるので省略。当初はWindowsのBashを使用したものの、WindowsからBashへのファイルのやり取りが面倒(逆はOK)だったので*追記あり、後半はmacOSへ移行した。どちらもnodebrewを使えば簡単に環境を構築できる。

npmでインストールしたモジュールは以下の通り。

  • express
  • ejs
  • http
  • compression
  • memory-cache
  • lru-cache

最後の3つは軽くパフォーマンスアップするもので無くても作動する。またサイトがhttpsの場合は、http(http.get)モジュールではなくhttpsモジュール(https.get)を使用する。

ここにコードを載せても載りきらないので要点はこんな感じだ。

  • Expressでのルーティング
    app.get(‘/’ …
    app.get(‘/page/:pages’ …
    app.get(‘/tag/:tags/page/:pages’ …
    app.get(‘/category/:categories/page/:pages’ …
    app.get(‘/post/:postId’ …
    ※例えば/pageといった、1ページだけのルーティングは省略
     
  • 各ルーティングで必要なデータをREST APIで得る
     
  • 一覧表示の各内容は、content.renderedにimgなどタグも含めそのまま入っているので、<!−−more−−>までで切り出す
     
  • paginateで必要な最大件数/最大ページ数はJSONにはなく、レスポンスヘッダのX-WP-TotalとX-WP-TotalPagesに入っているので、例えばhttp.get(url, (d)とすると、d.rawHeaders[]のn番目に先の文字列があり、n+1が欲しい値となる
     
  • REST APIで得たデータを加工してテンプレートejsへ渡す
    index.ejs(他の一覧も兼ねる)
    post.ejs

テンプレートはこの2本だけだが、実際はヘッダー、サイドバー、フッターなどを別ejsにしてincludeするよくあるパターン。htmlのフレームワークはお馴染みBootstrapだ。

API仕様の気になる点

プログラム自体は簡単だが、実際に動かして思ったのは、純粋に一覧だけ(title、date、categories、tags、featured_media程度のみ)得るAPIが無いため、何をするにしてもpostsでデータを得る必要がり、JSONのデータ量と、それを作るときのサーバー側の負荷(ショートコードやfunctions.phpの内容も展開する)が結構かかる。

加えてサムネイル画像を一覧に出そうとすると_embedオプションを付けなければならず、更にデータ量が増す。ここのように遅いサーバーだとその差は体感ではっきりわかるほどだ。

本家はたまたまアイキャッチ画像(featured_media)を使わず、記事の頭に大き目の画像を入れてあるので、これには引っかからなかったが、一般的には重い処理となるだろう。

本家にあって、こちらに無いのは「前後記事へのリンク」と「Archivesの年月一覧」。今のAPI仕様ではどうみても全件データを引っ張って解析しない限りこの2つには対応できないように思う。

一部クライアント側でレンダリング

一点手抜き(?)したのは、サイドバーの各一覧。これはサーバー側ではなく、クライアント側で書いている。もともとウィジェットを置く場所なのでこれもありかなと…。

ちょっとアクロバティックなのはPopular Posts。これはWordPress Popular Postsがウィジェットとして表示しているもので、実体はadmin-ajax.php?action=wpp_get_popularを呼ぶとリストのhtmlが戻ってくる形になっている。ただそのまま呼ぶとクロスドメイン制約で値を得られない。

そこで同じサーバー内にあるのを利用して、curlを使い一定間隔でそのhtmlをファイルへ保存、参照する形にしている。

これで無事表示は出来るのだがリンク先は本家。実験サイトではないため、このままだとあまり意味がない。また本家のURLはタイトルベース、実験サイトはIDベースなので、ドメインの部分だけ置換しても作動しない。

「うーん」と思っていたところ、表示するサムネイル画像のファイル名にIDが入っていることが分かり、それを使って実験サイトへのURLになるよう書き換えた(笑)

雑感

仕上げはサーバーへの設置だ。Proxyを設定するのが面倒なので、iptablesでポート3000を開けそのまま外に出している。この時、スクリプトをデーモン化する必要があり、forever -w start app.jsで起動。無事、外からアクセスできるようになった。

一式やってみた感想は、当初Node.jsの話を聞いたとき、既にいろいろあるのに何故今更JSと思ったが、サーバー側もクライアント側も全てJSで書け分かり易い上にデバックもし易く、これはありだ。

またテンプレートエンジンのEJSは、htmlそのまま<% %>の中だけJSの世界となりとっつき易い。つまり普段、LAMPを使っていれば、ベースの部分は何も学ぶ必要がなく、各モジュールの仕様だけ理解すれば(しかもJS)即扱える。これはなかなか楽しいかも知れない。

Node.js+Express+EJSで再構築したBLOGのViewはこちら

追記

「WindowsからBashへのファイルのやり取りが面倒」と書いたが、/mnt/c/Users/にWindowsのファイルシステムがマウントされているので、ここならどちらからでも普通にアクセスできる。

更にVisual Studio Codeの総合ターミナルをBashに変更すればかなりGoodな環境となる。

Visual Studio Codeの統合ターミナル
Visual Studio Codeの総合ターミナルでBashが作動中

方法はメニューのファイル/設定/基本設定/ユーザー設定で、

これを追加すればOK。もちろんviやnode app.jsもこの中でそのまま作動!