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:厳密にはデプロイするときの転送量削減効果がありますが、それはどうでもいいでしょう