快適アプリ開発Backbone.Marionette 第1回 Backbone.Marionetteとは

第1回目はBackbone.Marionetteはどのようなものか、その特徴や機能を概観します。Backbone.jsを使う際に頻出する機能を補完するライブラリなので、Webアプリ開発の効率が上がります。

発行

著者 山田 順久 フロントエンド・エンジニア
快適アプリ開発Backbone.Marionette シリーズの記事一覧

はじめに

本シリーズではBackbone.Marionetteについて取り上げます。Marionette、操り人形という言葉から思い浮かぶように、Backbone.jsに新たな機能を追加するライブラリです。Backbone.jsを利用したアプリケーション開発にどのような変化をもたらすのか、その上でアプリケーション設計をどのように行うのかを解説していきます。

なお、このシリーズは、Backbone.jsを使ったことがある方を想定して書かれています。Backbone.jsにまったく触れたことのない方は「Webアプリ構築のためのBackbone.js入門」シリーズなどを参考にしてもらえればと思います。

Marionette.jsとは

執筆現在(2014年2月中旬)の最新バージョンは1.6.1。

Marionette.jsとは、簡単に言うとBackbone.jsを利用したアプリケーション開発をもっと楽にしてくれるライブラリです(以下、Backbone.MarionetteをMarionette.jsと表記していきます)。

Backbone.jsは、すでにWebアプリケーションのフロントエンド実装のためのライブラリとして広く利用されています。クライアントサイドMVCの慣習に沿ってオブジェクトを分類し、それらが相互に作用し合って、アプリケーションの要求を満たしていくという設計を促すためのシンプルな指針を提供しています。

しかし、そのシンプルさゆえに、アプリケーション全体を統括するような仕組みや大規模化していくコードを、きれいに保つための仕組みまでは提供していません。そういった部分は、それぞれの開発者たちに委ねられています。これは状況に応じて柔軟な対応が取れるという点では、よいことですが、特にViewにおいては毎回同じようなコードを書いてしまうような場面もあります。

そこでMarionette.jsは、多くの場合に有効な実装パターンを取り込んで、開発者たちがこれから作るアプリケーションのためのコードに集中できる時間を増やすことを目指しています。さらにアプリケーション全体を管理する機能も加えることで、より大きな規模のアプリケーションを、もっと楽に作るためのライブラリとして公開されています。

Marionette.jsの構成要素

まずはMarionette.jsでできることを構成要素を見ながら概観してみましょう。Marionette.jsは主に次のような機能を提供します。

名前 役割
Marionette.Application アプリケーション全体の実行を管理する
Marionette.AppRouter URLに対する処理を行う
Marionette.Controller モジュール同士を繋ぐなど汎用的な役割を担う
Marionette.ItemView 1つのModelをViewとして扱う
Marionette.CollectionView Collectionを扱いItemViewを子Viewとして管理する
Marionette.CompositeView CollectionViewを継承し、より柔軟なDOMツリー構造を扱う
Marionette.Region DOM要素をViewをレンダリングするためのコンテナとして定義する
Marionette.Layout 複数のRegionとViewを管理する

それぞれ、このシリーズの後続の回で詳しく触れていきますが、ApplicationAppRouterControllerはViewやModelの間を取り持つ機能を担っています。ItemViewCollecttonViewCompositeViewRegionLayoutはそれぞれ異なった役割で、View周りのコーディングに役立つ機能を持っています。

Marionette.jsにできること

Marionette.jsから得られる恩恵は大小さまざまで、細かいものを挙げていくときりがないほどですが、大きなものを挙げるとすれば、次のような点があります。

  • モジュール化のサポート
  • 開発者が書かなければならないコード量の減少
  • 機能の部分的な利用

モジュール化のサポート

Marionette.jsの機能の中で大きなものとして、モジュール化のサポートがあります。モジュール化というのは、ある機能を表す抽象的なまとまりにソースコードを分解することです。

大規模なWebアプリケーションをきれいなコードに保ちながら作っていくためには、複雑な機能を細かな機能に分解して、その役割を果たすモジュールとして組み合わせていくことが大事です。また、それぞれのモジュールが自立できるように、互いにメソッドを直接呼び出したりといった依存関係は取り除いていく必要があります。

自立した小さなモジュールを保つことでテストもしやすくなり、たくさんのモジュールを組み合わせた大規模なアプリケーションを作ることができます。

Marionette.jsはそのモジュール化を助けるための、モジュールの定義と管理、そしてモジュール同士を連携させるためのイベントやメッセージングの機能を備えています。

次のコードはアプリケーション全体を管理するMarionette.ApplicationオブジェクトのインスタンスにListモジュールを定義して、アプリケーションを開始する例です。

// Marionette.Applicationインスタンスを作成
var Todo = new Marionette.Application();

// Todo.Listモジュールを定義
Todo.module('List', function(List, Todo, Backbone, Marionette, $, _) {

  // Todo.Listモジュールの初期化コードを記述
  List.addInitializer(function() {
    alert('List.addInitializerから呼ばれました。');
  });

});

// アプリケーションの開始
Todo.start();

Todo.start()でアプリケーションを開始すると、TodoアプリケーションのモジュールであるTodo.Listを定義するコードの中に書かれたaddInitializerメソッドに渡されている初期化処理も併せて実行されます。

これはほんの一例ですが、こうしてアプリケーションの開始に連動する初期化処理もモジュールを定義するコード自身の中に記述することで、コードの見通しをよくすることができます。

コード量を減らす

Marionette.jsはBackbone.jsによるアプリケーション開発におけるいくつかの便利な実装パターンをすでに取り込んでいます。

入れ子になるViewを扱う仕組みや、いくつかのイベントの追加などは、もしかしたらたいていのプロジェクトで、Backboneオブジェクトをベースにした同じようなカスタムオブジェクトが作られているかもしれません。そうしたよく必要とされる機能はMarionette.jsの方ではじめから用意されています。

ほかにも、Viewインスタンスを破棄する際のメモリリークの防止や、HTMLテンプレートとModelのデータを合わせてDOMツリーへ追加し、レンダリングを行うといったような処理も、ある程度自動的に行ってくれるようになっています。

このような機能があると、アプリケーションを作ろうとしたときに、開発者が自分たちで用意すべきコードの量というのは減ります。それらの汎用的な機能はMarionette.jsが担当する仕事となるので、その整備に煩わされることなく、自分たちのアプリケーションが果たすべき要求に集中して取り組むことができるようになります。

次のコードは簡単な例ですが、Backbone.Viewを継承したクラスによくあるrenderの実装です。

var SampleView = Backbone.View.extend({
  ...

  render: function() {
    var template = $('#template');
    var data = this.model.toJSON();
    var html = _.template(template, data);
    this.$el.html(html);
    return this;
  }

  ...
});

このような決まりきったパターンはMarionetteのViewに、すでに実装されているので、このパターンに沿っている限りは、renderメソッドの実装をこちらで書かなくてもかまいません。

次のコードではViewとして1つのModelを扱うMarionette.ItemViewを継承したクラスを定義しています。templateに渡しているのはscript要素で書かれたテンプレートのIDセレクタです。

var Contact = Backbone.Marionette.ItemView.extend({
  el: '#contact-region',
  template: '#contact-template'
});

HTMLはこのようになっているとします。

<div id="contact-region"></div>

<script type="text/template" id="contact-template">
  <dl>
    <dt>Name</dt>
    <dd><%- name %></dd>
    <dt>Age</dt>
    <dd><%- age %></dd>
  </dl>
</script>

そしてMarionette.ItemViewのインスタンスにModelを渡してrenderメソッドを実行するだけで、テンプレートを取得してModelのデータも適用してDOMツリーに挿入するところまでしてくれます。

var Person = Backbone.Model.extend({
  defaults: {
    name: 'Alice',
    age: 20
  }
});

var person = new Person();
var contact = new Contact({
  model: person
});

contact.render();

部分的な導入が可能

Marionette.jsのそれぞれの機能もまた、自立したモジュールとして互いに依存せずに、必要な場合に連携して働くように設計されています。

そのため、Marionette.jsを導入するにあたっては、先に挙げたMarionette.jsの機能のすべてを一度に導入する必要はなく、何か大きなルールに従うことになるということは起こりません。Marionette.jsのすべての機能について、あらかじめよく知っておかなければならないということもありません。

例えばMarionette.ItemViewや、Marionette.CollectionViewは使うけれど、Marionette.Applicationは使わないといった選択をすることができます。そのときには、Marionette.ItemViewMarionette.CollectionViewの仕組みについて知っておけば、まずは十分なのです。

したがって、自分たちのプロジェクトの中で、すでに確立した手法があれば、それをベースにして一部分だけMarionette.jsを取り入れたり、既存のBackbone.jsアプリケーションのコードを徐々にMarionette.js化していくようなこともできるだろうと思います。

Marionette.jsの使い方

Marionette.jsはBackbone.jsとその依存関係に加えて、Backbone.WreqrとBackbone.BabySitterに依存していますが、公式サイトからPre-packagedアーカイブをダウンロードすれば、必要なライブラリはすべて揃います。

Marionette.js - Downloads and Documentation

ダウンロードしたアーカイブを展開したら、backbone.marionetteフォルダ直下にあるファイル*を次のように読み込みます。

*注:直下にあるファイル

アーカイブを解凍したbackbone.marionetteフォルダ直下以外に、coreフォルダや、amdフォルダにもbackbone.marionette.jsファイルがありますが、こちらではありません。

<script src="jquery.js"></script>
<script src="underscore.js"></script>
<script src="backbone.js"></script>
<script src="backbone.marionette.js"></script>

Backbone.WreqrとBackbone.BabySitterはbackbone.marionette.jsのファイルに含まれていますので、明示的に読み込む必要はありません。

同梱されているjson2.jsライブラリは、古いバージョンのブラウザに対応する必要がある場合に読み込みます。

参考になるWeb上の文書

Marionette.jsについての文書は次に紹介するURLからも参照することができます。

リポジトリのdocsディレクトリにMarionette.jsが提供する各コンポーネントの解説があります。

GitHub Wiki ページも用意されています。

注釈付きのソースコードを読むこともできます。

Marionette.jsの作者、Derick Bailey氏によるアプリケーションサンプルと、そのGitHubリポジトリも参考になります。

まとめ

今回はMarionette.jsの概要について解説しました。次回から具体的なMarionette.jsの機能や使い方の解説をしていきます。