Post

Backbone.jsとHandlebars.jsを組み合わせる

Backbone.jsとHandlebars.jsを組み合わせる

Backbone.js でアプリケーションを作る場合、ついつい手軽さを求めてUnderscore.js の template()を使うことが多いのですが、少し凝った造りのページを作る場合、より専門的なテンプレートエンジンを使いたくなります。

そこで今回は、最近マイブームのHandlebars.jsを Backbone と組み合わせて使ってみました。

このエントリでお伝えしたいこと。

  1. Backbone.js with Handlebars.js!!
  2. ここでもやっぱり Grunt 最高

Handlebars.js とは

詳細は Google 先生の方が詳しいです(ごめんなさい)。
数あるクライアントサイドのテンプレートエンジンの 1 つです。個人的にはプリコンパイルすることでパフォーマンス的に優位なところを注目しています。

[jsperf]Precompiled Templates

最近話題の twitter のHorgan.jsともいい感じに渡り合ってます。

とは言っても、プリコンパイル前は激遅なんですが。。。

アプリケーション構成

まず、アプリケーションの構成は次のようなものだと仮定して話を進めます。

1
2
3
4
5
6
7
8
9
10
11
12
app
 ├ Gruntfile.js
 ├ hbs
 │ └ partial.hbs https://テンプレート
 └ js
   ├ views
   │ └ partial.js https://テンプレートをレンダリングするView
   ├ collections
   ├ models
   ├ template.js https://テンプレートがプリコンパイルされたJS
   ├ namespace.js
   └ app.js

namespace.js

1
2
3
4
5
6
var MyApp = {
  Views: {},
  Collections: {},
  Models: {},
  Templates: {},
};

なにはともあれ最初は Grunt!!

まず、なにか新しいことを始めるためには準備と計画が大事です。
特に Handlebars.js の場合は、プリコンパイルしない事には使い物にならないので、ビルドプロセスが必須です。 ということで Grunt のタスクを使います。

grunt-contrib-handlebars

Gruntfile.js は次のように書きます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
module.exports = function (grunt) {
  grunt.initConfig({
    https://some...

    handlebars: {
      compile: {
        options: {
          namespace: "MyApp.Templates",
          processName: function (filepath) {
            // input -> app/hbs/partial.hbs
            var pieces = filepath.split("/");
            return pieces[pieces.length - 1].replace(/.hbs$/, ""); https://output -> partial
          },
        },
        files: {
          "app/js/template.js": "app/hbs/*.hbs",
        },
      },
    },
  });

  // Load the plugin.

  https://some tasks...

  grunt.loadNpmTasks("grunt-contrib-handlebars");

  // Default task(s).
  grunt.registerTask("default", ["handlebars"]);
};

普段 Grunt 使っている人だったら、さっと見ただけで分かると思うので、compile オプションの大事な所だけ補足します。

namespace

プリコンパイルされたテンプレート関数が割り当てられます。デフォルトだとJSTとなるので必要な場合、設定してください。

processName

processName とは、(上の)namespase オブジェクトに格納された、プリコンパイル済みテンプレート関数を取り出すためのキーです。デフォルトではファイルパスが設定されるようになっており、次のように取り出すようになっています。var tmpl = MyApp.Templates["app/hbs/partial.hbs"];
個人的にはvar tmpl = MyApp.Templates.partial;と backbone 側から利用したいので、override しています。

これで Grunt の watch タスクと組み合わせることで、hbs ファイルに変更があった際に template.js として自動でプリコンパルされます。Grunt ってほんと便利!

Backbone と使う

さて本題です。 今回は、Backbone でありがちな、render()で Collection の中身を出力する場合を例に説明します。

まずは、Handlebars.js のテンプレート部分

1
2
3
4
5
6
<ul>
  <li class="id"></li>
  <li class="name">()</li>
</ul>

Backbone の View からは次のように呼び出します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
MyApp.Views.partial = Backbone.View.extend({

  https://partial.hbsで定義したテンプレート
  tmpl: MyApp.Templates.partial,

  https://some...

  render: function() {

    this.$el.html(
      this.tmpl({
        models: this.collection.toJSON()
      })
    );

  },

  https://some...

Handlebars.js のテンプレート関数にデータを渡す際に、1 回オブジェクトにラップして名前を付ける手間がありますが、これでBackboneでHandlebars.jsを使うことができました。 Handlebars.js には他にも色々な Expressions があるのですが、同じ原理で大丈夫なはずです。

This post is licensed under CC BY 4.0 by the author.