DOM Builder系のjsテンプレートエンジンまとめ

Posted by Hiraku on 2011-06-14

前回、どちらかと言えばinnerHTMLよりはDOMを使いましょうと書きました。しかしDOMをちょっと使えば、その余りの煩雑さに閉口することでしょう。では可読性を保持しつつ、XSSも考慮して書くにはどうすればいいでしょうか。

ちょっとしたものであれば、HTML中にdisplay:noneで構造を書き出しておき、それをJavaScriptから使う、というアプローチでもカバーできるでしょう。しかし大規模になると限界が見えてきます。描画に必要ない要素を書き出しすぎると、パフォーマンスの問題も発生します。

そこで、JavaScriptでもテンプレートエンジンを使うことになります。

テンプレートエンジンには二大勢力がある

E4Xみたいな変態拡張やJadeなどの独自文法系を除くと、Scriptlet系DOM Builder系の二種類に大きく分けることができそうです。(系統の名前は適当に決めました。正式名称があったら教えてください)

Scriptlet系

<ul>
    <% for(var i=0; i<supplies.length; i++) {%>
    <li><%= supplies[i] %></li>
    <% } %>
</ul>
  • PHPやJSPなどのようにHTML中にスクリプトを埋め込んでいく書き方をするもの。HTMLそのままを書けるためわかりやすく、テキストなら何でも書けるという汎用性を誇る。反面、気をつけないとタグエラーやXSS脆弱性が紛れ込む可能性もある。大抵の人が「テンプレートエンジン」と聞いて思い浮かべるのはこっち。
  • HTMLベースなのでJavaScriptに詳しくないデザイナーさんでも取っ付きやすいかも。
  • 数は多い。いろんな人がいろんなものを公開している。
  • 有名どころ:EJSなど。

DOM Builder系

var row1 = "abc",row2 = "def";
var template =
table(
  tbody(
    tr(
      td(row1),
      td(row2))));
  • JavaScriptの文法をフル活用し、素のJavaScriptでわかりやすくテンプレートを記述できるようにしたもの。要はDOM APIのラッパー関数集/言語内DSLの一種。タグの閉じ忘れが原理的に発生しない。XSSの危険性も少ない。しかしXMLやHTMLにしか使えず、文法が独特。ライブラリのサイズはコンパクトになる傾向がある。
  • JavaScriptがわかってないと、これでテンプレートを書くのは難しいかもしれない。
  • 関数を定義して短く書けるようにしたDSLタイプと、JSONをもとにDOMを構築するタイプがある。
  • 有名どころ:Mochikit.DOMなど。

DOM Builder系はあんまり有名なのがない気がする

発想としては昔からあるみたいですが、現在もメンテされ続けているものとなると少ないかも知れません。こちらも結構面白いアプローチなので、目についたものを集めてみることにしました。初期化のコードとかほぼ省略して、テンプレート本体の文法を並べていきます。

文法の比較をするのが主目的なので、あまり検証せずに掲載しています。もしかしたら動かないものとかあるかも知れません。間違いがありましたら指摘していただけると助かります。

Mochikit.DOM

Mochikitのモジュールの一つ。草分け的存在? mapなどの補助関数もあるみたい。分かりやすいけどTABLEとかTRみたいなグローバル変数を作りまくってるのなら、少し行儀が悪いかも。

TABLE({'class': 'prettytable'},
    THEAD(null,
        TR(null,
            TH(null, "aaa"),
            TH(null, "bbb"))),
    TBODY(null,
        TR(null,
            TD(null, "hoge"),
            TD(null, "fuga"))));

script.aculo.us:Builder

prototype.jsのアドオンとして有名なscript.aculo.usのモジュール。Mochikitに比べると冗長。

Builder.node('table', {className: 'prettytable'}, [
    Builder.node('thead', [
        Builder.node('tr', [
            Builder.node('th', "aaa"),
            Builder.node('th', "bbb")])),
    Builder.node('tbody', [
        Builder.node('tr', [
            Builder.node('td', 'hoge'),
            Builder.node('td', 'fuga')])])
]);

js-dom-builder

メソッドチェーンで書いていくアプローチを採用。タグを閉じるときは.end()を呼ぶ。

 domBuilder($get('basic'))
   .div({id: 'div1', style: 'height:50px;border-style:solid;border-width:4px;padding:1px;'})
     .div({style: 'float: left;' })
       .span().text('purple, ').end()
       .a({href: 'http://www.google.com'}).text('google').end()
     .end()
     .div({style: 'float: right;' })
       .span().text('cat').end()
     .end();

DOMMaker

dankogai氏作のもの。かなりシンプルに書ける。しかしメンテされてなさそう…

var e = new DOMMaker();
var template =
e.div({style:'background-color: pink'},
    'My Home Page is ',
    e.a({target:'_blank', href:'http://www.dan.co.jp/'}, 'Here'),
    '.',
    e.br(),
    'Thank You.'
);

nextile氏作のもの

script.aculo.usに似ているが、名前が短い。必要に応じてグローバル変数化できる。コードなにがし自体がサービス凍結中?なので、こちらもメンテナンス停止みたい。

$table(null,[
  $thead(null,[
    $tr(null,[
      $th(null, "aaa"),
      $th(null, "bbb")
    ])
  ]),
  $tbody(null,[
    $tr(null,[
      $td(null, "hoge"),
      $td(null, "fuga")
    ])
  ])
]);

jm === JavaScript Markup

node.js用。Markabyライクらしい。無名関数をひたすら重ねていくコールバックスタイル。

jm.render(function(b) {
    b.div({'class': 'foo'}, function() {
        b.img({src: "foo.jpg"});
    });
});

domjs

node.js用。ややこしいがCommonJSでDOM APIを実現したjsdomとは違うライブラリ。functionブロックで囲むというかなり変態的な文法。短く書ける。

var mytemplate = function () {
    header(
        h1('Heading'),
        h2('Subheading'));

    nav(
        ul({ 'class': 'breadcrumbs' },
            li(a({ href: '/' }, 'Home')),
            li(a({ href: '/section/'}, 'Section')),
            li(a('Subject'))));

    article(
        p('Lorem ipsum...'));

    footer('Footer stuff');
};

DOMBuilder

node.js、クライアントサイド両方で使える。文法はMochikit.DOMに似ているけれど、属性がない場合は省略でき、いちいちnullを書かなくてよい。また勝手にグローバル変数を増やしたりしない。

DOMBuilder.apply(window);
var article =
  DIV({"class": "article"},
    H2("Article title"),
    P("Paragraph one"),
    P("Paragraph two"));

とりあえずまとめ

個人的には最後のDOMBuilderに注目しています。ただ「これを使っていれば安心!」というライブラリはまだまだ挙げにくいですね。Mochikitやscript.aculo.usは大手なので安心感はありますが、ライブラリ依存になってしまうので、常にこれを使うことはできないでしょう。

盛り上がっているのはやはりnode.js界隈です。この辺りから本命が出てきそうな感じ。

今回、JSON系には一切触れませんでした。JSONは広くサポートされているので他言語との連携がやりやすいメリットはありますが、個人的には人力でテンプレートを書くときには向いていない気がします。

XML/HTMLをJSONで無理に表現すると、逆に冗長になるからです。JsonMLが一つの例ですね。XMLよりむしろJSONの方が長くなってしまってる。あれを手で書くのはちょっとなー…というところです。

とりあえず、テンプレートエンジンと言えばScriptlet系ばっかりな世の中ですが、DOM Builderはより「JavaScriptらしく」書けて面白いので、もうちょっと盛り上がるといいと思います。

私も作ってます

DOM Builderは面白い。しかしあんまり盛り上がってない。もったいない。ということで、私も作っています。

作っていますというか、nextile氏作のものをベースにしまして、カリー化を全面的に取り入れて「まだ短く書けるはずだ!」とウハウハしながら改造しまくった結果生まれたのがT.jsです。MITライセンスでgithubにて公開中です。

T.js DOMBuilder-like template engine for JavaScript

激しく車輪の再発明なので、いいライブラリがあったらマージしていきたいですね。次回、T.jsの紹介記事を書きます。つづく。



keyword: javascript

JavaScriptの最新記事