Durandal.jsに入門したはなし

唐突に名前がかっこよさそうなJSフレームワークを触って遊ぶことにしました👏
# Durandal.jsとは
![durandal.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18973/e6da8829-2b07-aa64-d2a4-e5560902899f.png)
そもそも**Durandal.js**とはなんなのか。

MVCでもMVPでもMVVMでもなんでもござれみたいな感じで公式には書いてあるがぱっとみではMVVMっぽい（そもそもKnockoutJSがのってるわけだし）

フレームワーク自体の特徴はどんなものなのか、ということでその謳い文句をチラと読んでみるとこんなことが書いてある。
> We didn't try to re-invent the wheel. Durandal is built on libs you know and love like jQuery, Knockout and RequireJS. There's little to learn and building apps feels comfortable and familiar. Dive in and enjoy.

どうやら**KnockoutJS**, **jQuery**, **RequireJS**と絡み合ってゴニョゴニョする
フレームワークらしい

調べてもあまり日本語の記事が出てこなかったので、国内ではあんまり有名じゃなかったのかな？ と思ったり、Githubの最新コミットが大体一年前でフレームワークの開発自体はもうそんなに活発じゃなかったりで、いろいろ調べているうちに明らかにチョイスが間違えていることに気づき始めたけれど、もう後戻りする時間がないので今回はこの若干出落ち気味のJSフレームワークを紹介します👏
# 試す
bowerが使えるのでそこからインストールする。

```bash:Bash
$ mkdir durandal-example
$ cd durandal-example
$ bower install durandal knockout jquery requirejs --save
```
jQueryはDurandalの依存関係を無視して最新版をいれないと、バージョンが古いせいで意味の分からないエラーがでるので注意。

インストールが終わったらindex.htmlとエントリポイントになるmain.jsを用意する

```html:index.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8" />
  </head>
  <body>
    <div id="applicationHost"></div>
    <script src="bower_components/requirejs/require.js" data-main="js/main.js"></script>
  </body>
</html>
```
```js:main.js
requirejs.config({
  paths: {
    "text": "../bower_components/requirejs-text/text",
    "durandal": "../bower_components/Durandal/js",
    "plugins": "../bower_components/Durandal/js/plugins",
    "knockout": "../bower_components/knockout.js/knockout",
    "jquery": "../bower_components/jquery/dist/jquery"
  }
});

define(function(require) {
  var app = require("durandal/app");

  app.title = "Durandal Example"
  app.configurePlugins({
    router: true,
    dialog: true
  });

  app.start().then(function() {
    app.setRoot('shell');
  });
});
```
なにかルートになるモジュールを用意する。この場合はshell.jsがそれにあたる。モジュールに対応するビューは同じ名前を持つのでこの場合はshell.htmlになる（後述）

```js:shell.js
define(function(require) {
  var app = require("durandal/app");
  var ko = require("knockout");

  var objects = {
    name: ko.observable(),
    sayHello: function() {
      alert("Hello! " + this.name());
    }
  };

  return objects;
});
```
```html:shell.html
<div>
  <label>Name</label>
  <input type="text" data-bind="value: name, valueupdate: 'afterkeydown'" />
  <button type="submit" class="btn" data-bind="click: sayHello">Say!</button>
</div>
```
はい、できましたね。「Say!」と書いてあるボタンを押すとダイアログがでます。

![スクリーンショット 2015-12-09 19.47.59.png](https://qiita-image-store.s3.amazonaws.com/0/18973/aa9abe7f-569c-2e9a-a2fc-5b90b1c5bca4.png "スクリーンショット 2015-12-09 19.47.59.png")

![スクリーンショット 2015-12-09 19.49.44.png](https://qiita-image-store.s3.amazonaws.com/0/18973/1931ce9e-ccfa-e6cf-ea6b-6e847a337ad6.png "スクリーンショット 2015-12-09 19.49.44.png")
# モジュール
http://durandaljs.com/documentation/Creating-A-Module.html

モジュールはRequireJSのdefine関数を使って定義できるもので、上の例ではshell.jsがこれにあたる。基本的にDurandal.jsではこのモジュールの組み合わせでアプリケーションを作っていく。

```js:モジュール
define(function(require) {
  return {
    ...
  };
});
```
定義されたモジュールのインスタンスは最初にrequireされるタイミングで生成され、常にシングルトンオブジェクトになる。

公式によれば、バックエンドサービスっぽいものを作りたいときはこんな感じでthisに生やしていけばよいとのこと。

```js:backend.js
define(function(require){
  var backend = function(user, data){
    this.user = user;
    this.data = data;
  };
 
  backend.prototype.someRoutine = function(){
    ...
  };
 
  return backend;
});
```
各モジュールは必ずモジュールIDを持っていて、特にオプションを使わなければmain.jsを起点にした相対パスがモジュールIDになる。`durandal/system`モジュールのgetModuleIdという関数を使っても、モジュールのインスタンスからIDを取得できる。
# ビュー
http://durandaljs.com/documentation/Creating-A-View.html

- Durandal.jsでは各モジュールがそれぞれルートになるひとつのビューを持っていて、ビューとモジュールのファイル名は同じになる（`A.js`に対応するビューのファイルは`A.html`、`B.js`のときは`B.html`みたいな感じ）
- 異なった名前のビューとモジュールを紐付けたい時には**viewLocater**というモジュールを使うらしいのだけれど、色々長くなりそうなので今回はやめておく（リファレンスページ: http://durandaljs.com/documentation/View-Location）
- このデータバインディングの機構のところでKnockoutJSが使われている

# コンポジション
http://durandaljs.com/documentation/Using-Composition.html

Durandal.jsには、**オブジェクトコンポジション**と**ビジュアルコンポジション**の2つがあり、後者がAngularJSのディレクティブ、Vue.jsのコンポーネントにあたるらしきもので、ビューを部分的に適用できる。

htmlだけをコンポジションとしてバインディングするのは非常にカンタン。

```html:header.html
<div>
  <h1>Header</h1>
</div>
```

```html:main.html
<div>
  <div data-bind="compose: 'header.html'"></div>
  <div>body</body>
</div>
```
あるいは、モジュール単位でのバインディングをしたいときには、拡張子を含めずにモジュールIDを渡せば良い。

```html:モジュールID指定
<div>
  <div data-bind="compose: 'header'"></div>
  <div>hoge</body>
</div>
```
この他にもビューとモジュールをそれぞれ別にひとつのコンポジションとしてバインディングする構文などいろいろあるらしいが、触れると厄介なことになりそうなのでここでは省略する。

# Pub&Subモデル
http://durandaljs.com/documentation/Leveraging-Publish-Subscribe.html

`durandal/events`というモジュールを使うと、イベント通知ができるようになる。特に説明すべきこともない名前通りの機能だが、違いとしてはイベントの送出がひとつの方向にしかないというところか。

```js:イベントの送出
app.trigger('customer:new', newCustomer);
```

```js:イベントのサブスクライブ
app.on('customer:new').then(function(customer) {
  ...
});
```
イベントに`all`を指定するとすべてのイベントをサブスクライブできる

```js:アプリケーションの全イベントをサブスクライブ
app.on('all').then(function(event) {
  ...
});
```

# プラグイン
ルーティングを紹介しようと思ったがいまいち直感的にわからなかったので力尽きた
http://durandaljs.com/documentation/Using-The-Router.html

# 所感
- Durandal.jsそんなに悪くなかった
- KnockoutJSを知ってるともっとよさそう

# 余談
Stackoverflowで見つけた[このスレッド](http://stackoverflow.com/questions/17416291/durandaljs-vs-angularjs)によると、Durandal.jsの開発者はすでにAngular 2.0のチームに合流しているとのこと。また、Durandalの後継にあたるフレームワークは**Aurelia**らしい。正直こっち触ればよかった。