実践入門 Ember.js

第1回Ember.jsの世界

はじめまして。佐藤竜之介@tricknotesと申します。本連載では、ユニークな特徴を持つJavaScriptフレームワークであるEmber.jsの仕組みと、実践での活用方法について解説させていただきます。

なぜEmber.jsか

ここ数年、ネイティブアプリケーションのような使い勝手を備えたWebサービスが増えています。筆者が利用しているサービスを例に挙げるとGmail, Pivotal Tracker, Idobataなどがあります。これらはどれも画面遷移がなく一枚の画面上であらゆる操作を行うため、⁠Webサイト」というよりは「アプリケーション」と表現する方が適切でしょう。このようなアプリケーションはシングルページアプリケーション(SPA)と呼ばれ、従来の画面遷移中心だったWebアプリケーションと区別されることがあります。

ただ、SPAの開発には特有の難しさがあります。それはデータと表示を常に一貫した状態に保つことやアプリケーションの「状態」を意識すること、オブジェクトのライフサイクルを考慮することです。これらの困難さを軽減するために、SPAを専門にサポートするフレームワークが注目を集めています。

こういったフレームワークはユーザインタフェースを取り扱うパターンである「MVC」にちなんで、⁠MV* フレームワーク」※1と呼ばれることがあります。

本連載で紹介するEmber.jsも「MV* フレームワーク」のひとつです。

emberjs.com

画像

Ember.jsって?

JavaScriptで開発をしていると「このコードいつも書くなぁ…」という状況に出くわすことはないでしょうか? 例えば、⁠オブジェクトの状態を監視して適切にDOMに反映する⁠⁠DOMのイベントを受け取ってデータを更新する⁠⁠DOMの生成・破棄のタイミングでイベントをon/offする」などの処理です。Ember.jsはそういった決まりきった処理をよしなに取り扱ってくれるため、プログラマはアプリケーションの使い勝手や期待通りの機能を満たせているかなどの本質的な部分の開発に集中できます。

もちろん、Ember.js以外にもたくさんの選択肢があります。AngularJSReactその他にもMV*フレームワークのサンプル集であるTodoMVCを見てみると、数多くのフレームワークやライブラリが存在していることがわかります。

Ember.jsを選ぶべき場面

では、私たちがEmber.jsを選ぶべきなのはどんな場面なのでしょうか?

一口に MV*フレームワークといっても、アプローチの仕方はそれぞれ異なります。Ember.jsを特徴付けるのは第一に「フルスタックである」ということが挙げられます。すなわち、リッチなアプリケーション開発のために必要な仕組みすべてを提供することをEmber.jsは目指しています。その結果として、Ember.jsの初期学習コストはその他の軽量なライブラリと比べると大きいと言えるでしょう。ただ、あなたの作ろうとしているアプリケーションがある程度の規模を持つならば、そのコストを差し引いてもEmber.jsの掲げる「高い生産性」の恩恵を十分に受けられることでしょう。しかしながら、素早いハックが求められる場面ならば他の選択肢を検討したほうがよいかもしれません。

本連載ではEmber.jsの機能についてひとつひとつサンプルを作りながら解説する予定なので、Ember.jsによる快適な開発を体感していただけると嬉しいです。

Ember.jsの歴史

ここからはEmber.jsに親しみを感じてもらえるよう、Ember.jsの誕生した背景を説明します。

SproutCoreの時代

Ember.jsはSproutCoreというMV*フレームワークから派生する形で誕生しました。SproutCoreはMac OS X用のアプリケーションを作成するためのフレームワークであるCocoaの設計思想をJavaScriptで実現しようという方針のもと開発されました。2008年当時、GUIアプリケーションのアイデアをWeb開発に持ち込んだというのは大変画期的で、それまでDOM操作が主流だったJavaScriptの世界に本格的なアプリケーションを作るための可能性が広がりました。

ただ、Webアプリケーションの世界ではHTML+CSSという表現力豊かな画面作成の基盤がすでにあったので、独自のやりかたでGUIを組み立てるよりも既存のやり方をそのまま利用できるほうがメリットが大きかったのです。そのため、当時SproutCoreのコアメンバーであったYehuda Katz氏はSproutCore 2.0を開発することを決意しました。

しかし既存の仕組みから大きく方針転換をするにあたって、単純にバージョンを上げるだけではその違いをアピールするのに不十分と感じたYehuda氏はフレームワークの名前を変えて再出発することを決めました。そうして開発が始まったのがEmber.jsです。2011年12月13日のことでした[2]⁠。

Ember.js正式リリース

Ember.jsの開発がスタートしてから正式リリースまでの間およそ一年半は何度も試行錯誤が繰り返されましたが、2013年5月1日にリリースされたバージョン1.0.0ではEmber.jsの方向性がしっかりと定まり、APIが安定したものになりました。

今現在ではYehuda Katz氏、Tom Dale氏を筆頭に多くのコミッターとEmber.jsコミュニティがその開発をサポートしています。

これからのEmber.js

バージョン1.0.0が出たからこれで完成、というわけではありません。本稿執筆時点での最新の安定版は1.8.1で、APIの改善や機能追加が継続して行われています。

そしてAngularJSやReactといった他のライブラリの優れたところを学びつつ、またあるときは他のライブラリに影響を与えつつ[3]⁠、MV*フレームワークのエコシステムの中で成長しています。その中から生まれた新しいアイディアは、Ember.js 2.0に向けたロードマップとして公開されています[4]⁠。

2.0と言ってもAPIがまったく変わってしまうわけではなく、現在のAPIをより洗練させていままでより直感的な記述ができるよう進化を続けているところです。

Ember.jsの特徴

さて、Ember.jsのバックグラウンドについて理解が深まったところで、次はEmber.jsの特徴を解説します。

Ember.jsはRuby on RailsからCoC(Convention over Configuration; 設定より規約)の理念を取り入れており、適切な名前付けを行うことでEmber.js本体が各クラス同士を結びつけアプリケーションを組み立ててくれるようになっています。そのため自明なコードを省略することができ、少ないコードで見通しよくアプリケーションを構築することができます。

Ember.jsの機能

では、Ember.jsの特筆すべき機能を見ていきましょう。

  • Auto updating templates
  • Routing
  • Components

Auto updating templates

Ember.jsではHandlebarsと呼ばれるHTMLに非常に近いテンプレート言語を使って画面を構築します。Handlebarsから生成されたHTMLでは、ユーザからの入力によってデータが変更されるとそのデータを表示している部分すべての表示が自動的に更新されます。この仕組みは双方向バインディングと呼ばれています。

Routing

Ember.jsでは画面にパーマリンクを割り当てることができます。パーマリンクを記録しておけば別のブラウザでアプリケーションを開いても同じ状態で表示することができます。また、別のユーザに特定のメニューを表示する手順を伝える際、"メニュー"->"設定"->"カスタマイズ"のような操作手順を伝えるのではなく、"http://example.com/settings/custom"のようなURLを伝えられる、ということが可能になります。

Components

HTML構造をまとめてひとまとめにして、独自の要素として扱うことができます。ComponentsはHTML構造だけでなく、イベントや内部実装をカプセル化します。例えば「"1分前"や"3日前"などの相対日付を表示するタグ」「ストップウォッチを実現するタグ」を作成して、アプリケーションに埋め込むことができます。これはHTML5で仕様策定が進められているWeb Componentsにインスパイアされて導入された機能で、将来的にはWeb Componentsとの統合も視野に入れられています。

環境準備

さて、それではいよいよ実際にEmber.jsを動かしてみましょう。

  1. Ember.jsと依存ライブラリをダウンロードします。

    本稿執筆時点でのEmber.jsの安定版は1.8.1です[5]⁠。

    ダウンロードしたら、これらをlibsディレクトリの下に置きます。

    .
    └── libs
        ├── ember.js
        ├── handlebars-v1.3.0.js
        └── jquery-2.1.1.min.js
  2. HTMLを用意します。

    index.htmlという名前で次の内容を保存します。

    <!DOCTYPE html>
    <html>
      <head>
        <script src="libs/jquery-2.1.1.min.js"></script>
        <script src="libs/handlebars-v1.3.0.js"></script>
        <script src="libs/ember.js"></script>
      </head>
      <body>
      </body>
    </html>

    index.htmllibsと同じディレクトリに配置します。

    .
    ├─⁠─ index.html
    └─⁠─ libs
  3. アプリケーションを初期化します。

    app.jsという名前で次の内容を保存します。

    // app.js
    App = Ember.Application.create();

    app.jsindex.htmllibsと同じディレクトリに配置します。

    .
    ├─⁠─ app.js
    ├─⁠─ index.html
    └─⁠─ libs

    index.htmlを編集してbodyタグの次のように書き換えます。

    <body>
      <script src="app.js"></script>
    </body>
  4. Templateを用意します。

    bodyタグの中に、次のコードを追記します。

    <script type="text/x-handlebars">
      <h1>Hi, {{name}}!</h1>
      My name is {{input value=name}}.
    </script>

ここまでで、次のようなファイル構成になっているはずです。

.
├── app.js
├── index.html
└── libs
    ├── ember.js
    ├── handlebars-v.1.3.0.js
    └── jquery-2.1.1.min.js

ではブラウザでindex.htmlを開いてみましょう。テキストフィールドに入力した文字がリアルタイムで画面上に反映される画面が確認できたでしょうか?

nameというプロパティを介して、ユーザからの入力とHTMLへの表示が同期されているのがわかります。これがEmber.jsの機能であるAuto updating templatesです。

次の画面が完成イメージです。

Ember.js example

その他の環境構築方法

また、この方法以外にもbowerEmber CLIといったEmber.jsが推奨するビルドツールで環境を構築する方法もあります。詳しくは公式サイトをご参照ください。

また、手軽にEmber.jsを触ってみるというだけでしたらEmber.js用のjsbinを使うという方法もあります。

お好みの方法で環境を構築してください。

Ember.jsの構成要素

ここまでだと、⁠動いているのはわかったんだけど、どうやって動いているのかわからない!」と感じている方が多いのではないでしょうか? それもそのはず、Ember.jsでは明示的に記述しなくてもいい部分が多いため裏側の仕組みがわかりづらいのです。そこで、ここからはEmber.jsの構成要素を紹介しつつEmber.jsが動作している仕組みを解説します。

今まで書いたコードで暗黙的に動いている部分は、明示的に書くこともできます。先ほどのサンプルと同等なアプリケーションを実現しようとすると、次のようなコードになります。

app.js
// Application
App = Ember.Application.create();

// Router
App.Router.map(function() {
  this.resource('index', {path: '/'});
});

// Route
App.IndexRoute = Ember.Route.extend({
  model: function() {
    var you = {name: null};

    return you;
  },
  controllerName: 'index',
  viewName: 'index'
});

// Controller
App.IndexController = Ember.ObjectController.extend({
});

// View
App.IndexView = Ember.View.extend({
  templateName: 'index'
});

また、テンプレートにもdata-templates-name属性を追加します。

index.html
<script type="text/x-handlebars" data-template-name="index">
  <h1>Hi {{name}} from Ember.js</h1>
  My name is {{input value=name}}.
</script>

いきなりコードが増えましたね。では、これらの要素を例に挙げつつEmber.jsの構成についてみてみましょう。

Ember.jsのアーキテクチャ
画像
  • Router … URLとRouteの対応付けを行います。
  • Route … Model, Controller, Viewの紐付けを行います。アプリケーションにパーマリンクを与える場合、その都度Routeを作成します。
  • Model … 画面に表示するモデルです。任意のJavaScriptオブジェクトを使うことができます。
  • Controller … Modelをデコレートして、ユーザからの入力イベントを処理します。また、アプリケーションの内部状態を保持する役割もあります。
  • View … DOMの操作やDOMからのイベントを扱います。
  • Template … Controller, ModelをHTMLに反映します。Handlebarsで記述します。

さきほどのサンプルの場合、URLの入力からHTMLの表示までは次のような流れで処理されます。

  1. App.RouterがURLをもとにApp.IndexRouteをアクティブにする
  2. App.IndexRoutemodelメソッドを実行して、画面に表示するモデルを取得する
  3. App.IndexRoutecontrollerNameプロパティからApp.IndexControllerを見つけ出しインスタンス化する
  4. App.IndexRouteviewNameプロパティからApp.IndexViewを見つけ出しインスタンス化する
  5. App.IndexViewtemplateNameプロパティからdata-template-name="index"のテンプレートを取得して表示に備える
  6. App.IndexRouteはmodel、controller, viewを結びつけ、templateに描画してHTMLを生成する

適切な名前付けによって自明なコードを省略することで、最初に作成したサンプルのようにとてもシンプルに記述することができます。

まとめ

今回はEmber.jsの歴史と特徴を紹介しました。次回からは簡単なアプリケーションを作成しながらEmber.jsの各機能について詳しく解説します。

おすすめ記事

記事・ニュース一覧