backbone-boilerplateではじめるHTML5アプリケーション開発 その2

前回のブログの続きです。
http://qualitas.hatenablog.com/entry/2014/05/21/045427

backbone-boilerplate のサンプルアプリである、github-viewer を見てみます。
tbranyen/github-viewer · GitHub

セットアップ

1. githubからクローンします

git clone git://github.com/tbranyen/github-viewer.git
cd github-viewer

2. 依存ライブラリをインストールします

npm install -q

と、ここでそのままインストールを行うと、grunt-karmaのインストールに失敗してしまったので、github-viewer/package.json ファイルの内容を以下のように変更しました。
※backbone-boilerplateのpackage.jsonの内容と同じ。

  "devDependencies": {
    "grunt": "~0.4.1",
    "bbb": "~0.2.0",
    "grunt-contrib-jshint": "~0.8.0",
    "grunt-contrib-cssmin": "~0.7.0",
    "grunt-contrib-copy": "~0.5.0",
    "grunt-contrib-clean": "~0.5.0",
    "grunt-contrib-compress": "~0.6.0",
    "grunt-processhtml": "~0.3.0",
    "grunt-karma": "~0.8.2",
    "grunt-karma-coveralls": "~2.3.0",
    "karma-jasmine": "~0.1.0",
    "karma-mocha": "~0.1.0",
    "karma-qunit": "~0.1.0",
    "karma-phantomjs-launcher": "~0.1.0",
    "karma-coverage": "~0.1.0"
  },

変更後、改めてインストール。

npm install -q

3. インストール後、gruntでサーバ起動

grunt server

ブラウザから、http://127.0.0.1:8000 にアクセスすると、github-viewerの画面が表示されます。
f:id:qualitas:20140527034420j:plain

このサンプルアプリは、GitHubAPIを呼び出します。
最初の検索文字には、Organizationを指定します。bocoupや、gruntjsなど。
すると、そのOrganizationに所属しているMemberのリストを画面に表示します。
Memberを選択すると、その人のリポジトリ一覧を表示し、リポジトリを選択すると、そのコミットログを表示します。

サンプルアプリの構成

このgithub-viewerは、もちろんbackbone-boilerplateをもとに作成されていますが、他に2つ、重要なライブラリを利用しています。
1つは、Backbone LayoutManager。もうひとつは、Lo-Dash Template Loaderです。

Backbone LayoutManager

tbranyen/backbone.layoutmanager · GitHub
のドキュメントの説明がわかりやすいので、そちらを見てください
https://github.com/tbranyen/backbone.layoutmanager/wiki/Overview

LayoutManagerを利用することで、テンプレートファイル(html)とViewを分離することができます。また、ネストされたViewの表示をするためのsetView や insertView のようなメソッドを提供してくれます。
以下は、.user-listというclassが設定されているul要素にItemViewを追加するコードです。

  var Layout = Backbone.Layout.extend({
    template: require("ldsh!./template"),

    serialize: function() {
      return { users: this.collection };
    },

    beforeRender: function() {
      this.collection.each(function(user) {
        this.insertView(".user-list", new Item({
          model: user
        }));
      }, this);
    },

    afterRender: function() {
      // Only re-focus if invalid.
      this.$("input.invalid").focus();
    },

    initialize: function() {
      // Whenever the collection resets, re-render.
      this.listenTo(this.collection, "reset sync request", this.render);
    },

    events: {
      "submit form": "updateOrg"
    },

    updateOrg: function(ev) {
      app.router.go("org", this.$(".org").val());

      return false;
    }
  });

まぁ、、今だと、Backbone.Marionette を使うほうがいいかもしれませんけどね。。

Lo-Dash Template Loader

もうひとつは、Lo-Dash Template Loader で、Lo-Dash(Underscore)のテンプレートファイル(html)を読み込んで(fetchして)、Viewのテンプレートに設定するためのRequireJSプラグインです。
tbranyen/lodash-template-loader · GitHub
LayoutManagerと組み合わせることで効果を発揮します。
以下のように、ldsh!の後ろにテンプレートファイルのパスを指定します。※拡張子は除く

      // Use main layout and set Views.
      var Layout = Backbone.Layout.extend({
        el: "main",

        template: require("ldsh!./templates/main"),

        views: {
          ".users": new User.Views.List({ collection: this.users }),
          ".repos": new Repo.Views.List({ collection: this.repos }),
          ".commits": new Commit.Views.List({ collection: this.commits })
        }
      });

RequireJSのtextプラグインで、'text!templates/main.html' のようにするのと似ています。

textプラグインと同様、このLo-Dash Template Loaderも、ビルド時にテンプレートファイルを最適化してくれます。
つまり、ビルド時に最適化したjsファイルにテンプレートファイルの内容を埋め込んでくれます。
ただ、textプラグインと異なるのは、このLo-Dash Template Loaderは、テンプレートファイルをコンパイルした状態でjsファイルに埋め込んでくれるところです。※ _.template()を行った後のテンプレートファイルを埋め込みます。
そのため、backbone-boilerplateでリリースビルドしたアプリは、実行時のView表示のタイミングで、htmlファイルのfetchや、テンプレートのコンパイルを行う必要がなく、View表示の速度が向上するように工夫されています。

リリースビルド

最後に、github-viewerをリリースビルドして実行する方法について記載します。
ローカルPCでリリースビルドをして実行する方法は、以下のようにgruntタスクを実行します。

grunt default server:release

ただ、実行してみると、backbone.collectioncach が動作しようとするところでエラーになります。このサンプルアプリを動作させるのに、backbone.collectioncacheは特に不要なので、利用しないようにソースを変更します。
config.jsのbackbone.collectioncacheの設定をコメントアウト

require.config({
  paths: {
    // Make vendor easier to access.
    "vendor": "../vendor",

    // Almond is used to lighten the output filesize.
    "almond": "../vendor/bower/almond/almond",

    // Opt for Lo-Dash Underscore compatibility build over Underscore.
    "underscore": "../vendor/bower/lodash/dist/lodash.underscore",

    // Map `lodash` to a valid location for the template loader plugin.
    "lodash": "../vendor/bower/lodash/dist/lodash",

    // Use the Lo-Dash template loader.
    "ldsh": "../vendor/bower/lodash-template-loader/loader",

    // Map remaining vendor dependencies.
    "jquery": "../vendor/bower/jquery/jquery",
    "backbone": "../vendor/bower/backbone/backbone",
    "bootstrap": "../vendor/bower/bootstrap/dist/js/bootstrap",
    "layoutmanager": "../vendor/bower/layoutmanager/backbone.layoutmanager"
//    "collectionCache": "../vendor/backbone.collectioncache"
  },

  shim: {
    // This is required to ensure Backbone works as expected within the AMD
    // environment.
    "backbone": {
      // These are the two hard dependencies that will be loaded first.
      deps: ["jquery", "underscore"],

      // This maps the global `Backbone` object to `require("backbone")`.
      exports: "Backbone"
    },

    // Backbone.CollectionCache depends on Backbone.
//    "collectionCache": ["backbone"],

    // Twitter Bootstrap depends on jQuery.
    "bootstrap": ["jquery"]
  }
});

また、router.js の collectionCache の読み込み処理をコメントアウト

  var Commit = require("components/commit/index");
  var User = require("components/user/index");
  var Repo = require("components/repo/index");

  // require("collectionCache");

これでリリースビルドしたサンプルアプリが動作するようになります。