Ext.Next – もうすぐそこに

この記事は Sencha Advent Calendar 2013 – Adventar の23日目です。 年も押し迫ってきましたね。 前回のyasunagaさんのExt.Menuに関する興味深い話 に続いて、今日はExt JSの未来について語ります。

この記事は、 SenchaUG 誕生祭 のLTで話したことを元ネタにしています。 あの時は、マクラの話が長すぎて肝心の内容を端折ってしまいましたw ので、ブログ化しました。

Ext JS の目指すところ

Sencha では、Ext JSの目指すところとして次の3つを挙げています。

  • ビジネス/データリッチアプリケーション
  • スケーラブルで保守性の高いコード
  • 後方互換性/デバイス互換性

後方互換性について、強く意識してもらっているのは本当にありがたいことです。

その中で、次世代の Ext JS では、どんの事が実現されるのでしょうか。

まず、タッチオペレーションがサポートされます。 デスクトップデバイスでもタッチオペレーションができるものが増えてきました。 それらに対応するためにも、Ext JSでもタッチオペレーションをサポートする必要が出てきたのですね。

そこでは、タッチ/クリックをうまく共通の方法でハンドリングする方法が用意されます。 ソースコードではclickイベントにリスナーを書いておくと、タッチイベントを使うデバイス上では、tapイベントにトランスレートしてくれるようになります。 そうすることで、プログラマがそれらの調整をしなくてもよくなります。

Ext JSでもタッチオペレーションが使えるとなると、Sencha Ext JSとSencha Touchの間でも共通の動作にすることができます。 つまり、Touchでもclickイベント書けば、tapが取れるようにしてくれたりするかな?と。 高岡さんの記事にもありましたように、Ext JSとTouchのコア部分は共通のところが多いのですが、微妙な違いがあります。 両方のフレームワークでの開発の経験がある人にとっては、この違いに悩まされたりハマったことがおありだと思います。

Common Core

Sencha Con 2013でのセッションで、Common Coreという概念が発表されました。 Ext JSとSenchaのCoreパッケージを共通化するというものです。

これを待っていました。 Sencha Coreパッケージが目指すのは次の二つです。

  • Consistency – 一貫性
  • Compatibility – 互換性

Senchaフレームワークの機能のうち、どの部分がCoreパッケージに入るのでしょうか。

  • 機能や環境の検出
    • Ext.env, Ext.feature, Ext.browser, Ext.os, Ext.supports, Ext.is
  • ユーティリティ
    • XTmeplate, Ext.Array, Ext.Object
  • クラスシステム
  • ダイナミックローダー
  • モーメンタムスクローラー
  • イベントシステム
  • ジェスチャーの認識
  • Ext.dataパッケージ

これらがCoreパッケージとして共通化されたら、大変素晴らしいことです。 Ext JSとTouchを使って、デスクトップ版とモバイル版のアプリを作る、というような用途の場合には、バックエンドとの接続部分などコードの多くの部分を共通化して使うことができるようになります。 現状のExt JSとTouchではそのようなことはできません。クラスシステムの構成の方法が微妙に違い、Ext.dataパッケージでのクラスの書き方が異なっているためです。

ここに挙げられたCoreに盛り込まれる予定の機能の中で、双方でほとんど変わりが無いものもあります。 しかし、大きく違う部分もあって、後方互換性を維持しながらこれを実現するのは大変難しいように思います。 特にクラスシステムに関しては、それが全ての土台ですから、どのようにして共通化するのか非常に興味があります。

早く実現して欲しいな。

Ext.Next

Sencha Con 2013では、今後Ext JSに追加されてゆく機能としては次のものが発表されました。

MVC Routing

Routingと聞いて「ははぁ」となるのは、Sencha Touchのエンジニアでしょう。 Ext JSのエンジニアにとっては聞き慣れない言葉でしょうね。

これはシングルページアプリであるExt JSアプリの中で、ヒストリーとディープリンクを使って、ブラウザの戻る/進むでのオペレーションや、URLによって直接その画面に移動することができるようにする機能です。 これは、http://example.com/hoge/#!fugaのようにハッシュを使います。 このハッシュに対応するコントローラーメソッドを定義してあげます。 必要であれば、メソッドを実行する前にBeforeフィルターといわれるチェックルーチンを通して、条件を満たさない場合はメソッドの実行をキャンセルすることもできます。

Routingがどんなものかに関しては、 こちらの資料に詳しいです。

この機能がExt JSでも使えるようになるんですね。

Grid

グリッドの機能がアップします。 Ext JSの目玉コンポーネントの一つがGridコンポーネントです。 始めてExt JSを見た人は、このGridの多機能さに驚きます。 そして、これだけ複雑なことをやっているのに、充分なパフォーマンスを発揮してくれます。 SenchaとしてもGridは最も重要なコンポーネントの一つとして認識しているので、常にパフォーマンスアップや機能アップを続けています。 次回もその両面からの強化がなされるようです。

Cell更新

GridColumn(Ext.grid.column.Column)には、rendererというコンフィグがあるのはご存じだと思います。 ここに関数オブジェクトをセットするとグリッドのセルの内容を自由に秒かできるようになるとても便利な機能です。 現在のrendererでは、recordが丸ごと渡されます。rendererの中ではそれを使って自由無っ事ができます。 便利ですね。

ですが、その副作用として、rendererの中でどのフィールドを使って描画しているか、フレームワーク側ではわからないので、どのフィールドが変更されたときにでもそのセルの内容をupdateする必要があります。 これは非常に無駄が多く、パフォーマンスを下げる原因となっています。

それを解消するために、dependsコンフィグと、updaterメソッドを導入します。

columns: [{
    text: '% Change',
    dataIndex: 'fieldName',
    depends: ['field2', 'field3'], // 依存するフィールドを定義する
    renderer: ...,

    // 画面を更新するロジックを書く
    updater: function(el, v, record) {
        var sp = Ext.fly(el).down('span', true);
        sp.style.color = (v < 0) ? 'red' : 'green';
        sp.firstChild.data = Ext.util.Format.number(v, '0.00');
    }
}]

このように、依存するフィールドをちゃんと定義してあげれば、どのフィールドに変更があったときに、どのカラムを更新知れば良いかわかります。 また、rendererとは別にupdaterを用意することで、更新時の処理を書いてやることができます。

Gadgetカラム

Sencha Con 2013のキーノートでもどよめきが起こったGadgetカラム。 これまでExt JSへの要望の中で、Gridのセルの中にいろいろなコンポーネントを配置したいというのがあったそうです。 ただ、それをやろうとすると中々大変だったようで、メモリーリーク問題も発生したそうです。

そこでSenchaのエンジニアは、Gadgetというものを考えました。 Gadgetsは、フライウェイトコンポーネントです。 各セルに配置されるコンポーネントが一つひとつインスタンスを持っていると大変ですから、フライウェイトオブジェクトとして、そのカラムのセルから共有されるオブジェクトとします。 こうした仕組みで、コンポーネントをセルの中に入れ込む方法を作り上げたんですね。

columns: [{
    xtype: 'gadgetcolumn',
    dataIndex: 'status',
    gadget: 'progressbar'
}, {
    xtype: 'gadgetcolumn',
    gadget: {
        type: 'button',
        text: 'Remove'
    }
}, {
    xtype: 'gadgetcolumn',
    dataIndex: 'size',
    gadget: 'slider'
}, {
    text: 'Trend',
    gadget: {
        type: 'sparkline.line',
        width: '100%',
        tipTpl: 'Price: {y:number("0.00")}'
    }
}]

Gadgetカラムの設定例です。xtypegadgetcolumnで、gadgetコンフィグにどんなGadgetなのかを定義します。

  • progressbar: プログレスバー
  • botton: ボタン
  • slider: スライダー

最後の一つは、チャートのガシェットです。 Sencha Conでは、グリッドの中のグラフがリアルタイムで表示が更新されるデモをしていましたね。

その他の新機能

フォームには、新しいフィールドコンポーネントが追加されます。

  • Ext.picker.Color
    カラーピッカーですね。
  • Ext.button.Segmented
    Touchでおなじみのセグメンテッドボタンです。
  • Ext.form.field.Tag
    タグ入力フィールドです。

BorderレイアウトでRegionグループというのが導入されます。 ドラッグアンドドロップで、リージョンを変更できる。 そしてRegionグループの表示方法はタブ/アコーディオン/ボックスに切り替えられます。 これはスゴイです。SenchaConのビデオで実際に動かしている様を見ることができます。

MVVM

Model / View / ViewModel のアーキテクチャーを導入するのです。 MVVMは、WPFから生まれたアーキテクチャーだそうですが、WPFではビューをXMLのようなもので記述するようですが、 それと似た感じで、htmlのような形式で記述するようです。

  • View を html5 形式で記述

    {firstItemLabel} {secondItemLabel} {thirdItemLabel}

            <list model="users">
            <itemTmplate>
                    <list-item>
                    {user.firstName}
                    {user.lastName}
                </list-item>
            </itemTmplate>
        </list>
    </cards>
    

こちらがビデオのスクリーンショットから盗んだビューのサンプルのコードです。 何を定義しているかは、見ればわかりますね。 プレースホルダのようなものも見えます。 確かにこれでUIを定義するのは楽かもしれません。 特にJSを書きたくないデザイナーさんにとっては朗報かもしれませんね。

しかしこれは非常に大きな変更です。 これまでの開発手法からどのように移行していくのか非常に興味があります。 あるいは共存していくのでしょうか。

ともあれ、来年はとても大きな変化が起きることと思います。 お楽しみに。