CouchDB サーバーサイドのテンプレートエンジンにEJSを使う。

CouchDB 0.9.0 から show/list など、サーバーサイドでレンダリングを行う機能が追加されました。これは普通に使うとすごく使いにくいので、通常はCouchAppを使って次のように書きます。例えば_show/sample を実装するとき。

function(doc, req){
   // !code vendor/couchapp/template.js
   // !json templates/sample
   
   return template(templates.sample, {doc : doc});
}

couchapp push コマンドでスクリプトCouchDBにデプロイできますが、// ! が重要なマクロ展開の機能を持っています。

!code により template.js の内容が couchapp push 時に展開され、デザインドキュメントの中に埋め込まれます。これは #include と同じだと思ってもらっていいでしょう。
!json

var template = {}; 
template.sample = "templates/sample.htmlのファイルの内容を展開"; 

のような形で展開されます。ここまでが前置き。

で、この template.js なのですが、template(string, {k1: v1, k2: v2, ... })のような形で実行し、string 部分をテンプレート、 {k1:v1, ...} 部分をテンプレート内で使用可能な変数として、展開した結果を返す関数を持っています。つまりこんな感じで templates/sample.html テンプレートが書けるのです。

<!-- templates/sample.html -->
<h1><%= doc.title %></h1>

これはこれで、通常問題ないのですが、このテンプレートエンジンは貧弱です。if や for などの条件分岐が使えません。なので、10回出力したい、とかいう話になると、次のように JavaScript 側で対応しなければなりません。

function(doc, req){
   // !code vendor/couchapp/template.js
   // !json templates/sample

   var str = "";
   for(var i=0; i<10; i++){
      str += template(templates.sample, {doc: doc, i: i});
   }   
   return str;
}

こうなると、PHPよりたちが悪いですね。ということで、いろいろJavaScriptのテンプレートエンジンを調べてみましたが、個人的には http://embeddedjs.com/ がよさそうです。

このライブラリ、prototype.js に依存していて、基本はクライアントサイドで使うのですが、prototype.js に依存した部分を踏まなければ、サーバーサイド(spidermonkey)でも使えました*1

CouchApp環境で EJS をゲットしたら、本番環境用の、ejs_production.js というファイルがあるので、それを vendor/ejs/ejs_production.js 辺りに配置しておきます。あ、ejs_production.js を無理して使わなくても、無圧縮の ejs.js でもいいです。圧縮されているかどうかはサーバーサイドで実行するJavaScriptにとってはどうでもいいので*2

で、EJS を使うときは new EJS({text: "テンプレート文字列"}).render({変数}); のようにするとよいようです。

先ほどの10回出力は次のようにできます(HTMLテンプレートの中でループ変数も使えます、ということを示す例)。

function(doc, req){
   // !code vendor/ejs/ejs_production.js
   // !json templates/sample
  return new EJS({text: templates.sample}).render({doc : doc});
}
<!-- templates/sample.html -->
<% for(var i=0; i<10; i++){ %>
<h1><%= doc.title %>[<%= i %>]</h1>
<% } %>

というわけで、CouchApp の開発には、EJSが断然おすすめ!! EJSはActionViewを意識したヘルパー関数もあって、form_tag とか link_to とか使えるんですよ!!!

実際、WebJourney で Rails部分をCouchApp に移行しているのですが、ActionView のノリでテンプレートが書けるようになったので、快適です。

*1:ここが重要。いくつかのJavaScriptのテンプレートエンジンは、グローバル変数を汚しにかかる実装になっていてサーバーサイドではそもそも動かないものが。。。

*2:厳密にはデプロイするときの転送量削減効果がありますが、それはどうでもいいでしょう