Knockout.js の Utility や Plugin (programming, debugging, monitoring) #html5biz


環境 : Visual Studio 2013 Update 2

こんにちは。

昨日の KnockoutJS 勉強会では、プログラミングやデバッグを支援する Tools Support や Plugin について簡単に紹介させていただきました。
使用したツール、コード、参照 URL (ドキュメント) 等を掲載しておきます。

 

Programming Support

以前「Visual Studio 2013 の Single Page Application (SPA) テンプレートを使った開発 (Knockout.js)」でも紹介したように、最新の Visual Studio を使用すると、マークアップ (data-bind 属性) の補完を含めた knockout の intellisense が使えます。(下図)

こうした Knockout まわりの補完機能は、Visual Studio 2013、Visual Studio 2013 Update 2 とバージョンがあがるごとに進化しています。
例えば、Visual Studio の ASP.NET SPA のプロジェクト テンプレートが作成するコードは、大雑把に書くと下記のような Partial View を使った実装になっていますが、最新の Visual Studio 2013 Update 2  では、このようなケースでも、ちゃんと _Home.cshtml で上図のようなコード補完 (Intellisense) が使えます。(もう、その次のバージョンの Preview, CTP などが出てきてますが。。。)

Index.cshtml

<!DOCTYPE html>

<html lang="ja">
<head>
  . . .
</head>
<body>
  . . .
  <div class="container body-content">
    . . .
    @Html.Partial("_Home")
    . . .
  </div>

  @Scripts.Render("~/bundles/jquery")
  @Scripts.Render("~/bundles/bootstrap")
  @Scripts.Render("~/bundles/knockout")
  @Scripts.Render("~/bundles/app")
</body>
</html>
_Home.cshtml

<!-- ko with: home -->
  . . .
  <!-- you can use intellisense here !-->
  <p data-bind="text: myHometown"></p>
  . . .
<!-- /ko -->

また、これを以下のように書き換えてみましょう。下記では、with を Partial View の外に移動しました。(Knockout.js の with の役割については、「Knockout.js で Multiple View (Partial View) をエレガントに切り替える方法」を参照してください。)
コードの意味は上記と同じですが、この場合は、コード補完 (intellisense) は使えなくなってしまいます。

Index.cshtml

<!DOCTYPE html>
<html lang="ja">
<head>
  . . .
</head>
<body>
  . . .
  <div class="container body-content">
    . . .
    <!-- ko with: home -->
    @Html.Partial("_Home")
    <!-- /ko -->
    . . .
  </div>

  @Scripts.Render("~/bundles/jquery")
  @Scripts.Render("~/bundles/bootstrap")
  @Scripts.Render("~/bundles/knockout")
  @Scripts.Render("~/bundles/app")
</body>
</html>
_Home.cshtml

  . . .
  <!-- sorry, you cannot use intellisense here... -->
  <p data-bind="text: myHometown"></p>
  . . .

このような場合、Visual Studio 2013 Update 2 以降では、下記のようなエディター用のキーワードを入れることで Intellisense を有効化できます。

_Home.cshtml

<!-- ko-vs-editor viewModel: window.app.Views.Home -->
  . . .
  <!-- Now, you can use intellisense in this part !-->
  <p data-bind="text: myHometown"></p>
  . . .
<!-- /ko-vs-editor -->

Knockout のプログラミングでは、Visual Studio が標準で提供しているユーティリティやライブラリー以外に、NuGet で提供されているパッケージ (Knockout.js の Plugin) も把握しておくと便利です。
例えば、Knockout.Mapping (knockout.mapping) は、Ajax などで取得した JavaScript のオブジェクトと ViewModel の mapping を容易にします。(使い方は Knockout.js ドキュメントの Mapping を参照してください。)
さらに、Knockout ViewModel (knockout.viewmodel) は、こうした mapping に加え、さまざまな ViewModel の processing option を提供し、より複雑な ViewModel を構築する際などに使えます。
また、Knockout Validation (knockout.validation) は、Visual Studio の SPA (Single Page Application) のテンプレートで既定でインストールされています。
なお、こうした追加のライブラリーでインテリセンスを使うには _references.js に参照を追加しておきましょう。

また、上図を見てお気づきの通り、Knockout.js と主要な Plugin においては、TypeScript 用の定義ファイルも Community により提供されています。
TypeScript と組み合わせることで圧倒的な生産性を手に入れることができますので、Knockout.js 開発においても是非活用してみてください。(Knockout.js を使った Typescript のプログラミングについては、鈴木さんが提供されている「Knockout.js 日本語ドキュメント : TypeScript + Knockout ES5 でさらにシンプルに」が参照になります。)

他にも、昨日デモでご紹介した Knockout Generator (Visual Studio の拡張機能です) など、Development support の拡張機能が提供されています。

補足 : WebStorm における KnockoutJS

今回興味があって調べてみたのですが、ドキュメントを見ると WebStorm 8.0 になって新たに AngularJS サポートが追加されたようですが、残念ながら、Knockout.js はサポートされていません。(Knockout.js では、下図のようなマークアップの code completion が使用できません。)

ただ、JavaScript や TypeScript の code completion (Visual Studio の intellisense 類似の機能) には対応しています。
WebStorm の Project settings の画面を開き ([File] - [Setting] メニューを選択します)、下図の通り [JavaScript] - [Libraries] の箇所で Library を Download したり、あらかじめ Downlaod しておいた Library を指定するなどして、Knockout.js の code completion を有効化できます。(Knockout.js のライブラリー自体は、Terminal を使って bower からインストールすることもできます。)

TypeScript の場合には、下図の通り、Downlaod ファイルの種類として [TypeScript community stubs] を選択します。(*.d.ts の定義ファイルがダウンロードされて、洗練された code completion が可能になります。)

私も先日の Build Insider OFFLINE (TypeScript 勉強会) の LT を見て関心してしまいましたが、WebStorm 8.0 では「JetBrains WebStorm Blog : Enjoy TypeScript in WebStorm」で紹介しているように、VS + Web Essentials バリの強力な TypeScript 支援を提供していますので、組み合わせて使うとかなり快適に開発できそうですね。

 

Monitoring and Debugging Support

Knockout.js の Debug や Monitoring については、紹介した本家のブログ「Knock Me Out – Knockout.js Troubleshooting Strategies」にまとまっていますので、是非読んでみてください。

例えば、observable, observableArray, computed などの subscribable の argument チェックをおこなう場合には、Extenders を使用すると便利です。
下記の太字は、ViewModel (この場合は orderViewModel) のすべての subscribable (observable, observableArray, computed) に extender を設定することで、値の変更がある度に、その結果を console に出力しています。(元のコードは汚していない点に注目してください。)

<!DOCTYPE html>
<html>
<head>
  <meta name="viewport" content="width=device-width" />
  <title>Index</title>
  <script src="~/Scripts/jquery-1.10.2.min.js"></script>
  <script src="~/Scripts/knockout-2.3.0.js"></script>
  <script type="text/javascript">
  $(document).ready(function () {
    // ViewModel
    function OrderViewModel() {
      var self = this;
      self.itemname = ko.observable("Test Product");
      self.price = ko.observable(100);
      self.unit = ko.observable(0);
      self.total = ko.computed(function () {
        return self.price() * self.unit();
      });
      self.add = function () {
        self.unit(self.unit() + 1);
      };
    };

    // Model Initialize
    var orderViewModel = new OrderViewModel();
    ko.applyBindings(orderViewModel);

    // trace for all subscribable
    // (observable, observableArray, computed)
    ko.extenders.LogText = function (target, option) {
      target.subscribe(function (newValue) {
        console.log(option.propName + ": " + newValue);
      });
      return target;
    };
    for (var prop in orderViewModel) {
      if (!ko.isSubscribable(orderViewModel[prop]))
        continue;
      orderViewModel[prop].extend({ LogText: { propName: prop} });
      console.log("log set for: " + prop);
    }
  });
  </script>
</head>
<body>
  <div> 
    <p><span data-bind="text: total"></span> Yen</p>
    <button data-bind="click: add, text: 'Add Unit'" />
  </div>
</body>
</html>

Chrome や Internet Explorer を使って実行すると、下記の通り console に結果が出力されるのが確認できます。

また、下記のコードを見てください。
このサンプルでは、下記太字の「totals」は存在しないので Binding error となります。

<!DOCTYPE html>
<html>
<head>
  <meta name="viewport" content="width=device-width" />
  <title>Index</title>
  <script src="~/Scripts/jquery-1.10.2.min.js"></script>
  <script src="~/Scripts/knockout-2.3.0.js"></script>
  <script type="text/javascript">

  . . . (上記同様)

  </script>
</head>
<body>
  <div> 
    <p><span data-bind="text: totals"></span> Yen</p>
    <button data-bind="click: add, text: 'Add Unit'" />
  </div>
</body>
</html>

このような Binding error を trap して何か確認をおこないたい場合は、下記太字の通り ko.bindingProvider を使用します。(なお、こうした Binding error の場合、通常でも、Knockout.js のライブラリーがエラーを出力します。より詳しく中身を trap したい場合などに、下記の通り実装すると良いでしょう。)

<!DOCTYPE html>
<html>
<head>
  <meta name="viewport" content="width=device-width" />
  <title>Index</title>
  <script src="~/Scripts/jquery-1.10.2.min.js"></script>
  <script src="~/Scripts/knockout-2.3.0.js"></script>
  <script type="text/javascript">
  $(document).ready(function () {
    var existing = ko.bindingProvider.instance;
    ko.bindingProvider.instance = {
      nodeHasBindings: existing.nodeHasBindings,
      getBindings: function (node, context) {
        console.log("Intercepted getBindings");
        var bindings;
        try {
          bindings = existing.getBindings(node, context);
        }
        catch (ex) {
          // when binding error occurs, comes here.
          // (do some kind of check)
          console.log("Captured binding error",
            ex.message, node, context);
          . . .
        }
        return bindings;
      }
    };

    . . . . .

  </script>
</head>
<body>
  <div> 
    <p><span data-bind="text: totals"></span> Yen</p>
    <button data-bind="click: add, text: 'Add Unit'" />
  </div>
</body>
</html>

この他にも、「Knockout.js の依存の更新タイミングと rateLimit」で紹介したように、Performance 最適化の観点などで呼び出し回数をモニタリングしたい場合などには、ko.bindingHandlers を使用すると良いでしょう。(コードは省略します。)

また、「Knock Me Out – Knockout.js Troubleshooting Strategies」では、こうした Trace などを補助してくれるユーティリティ (ツール) も紹介しています。

お勧めは、Chrome の extension である Knockoutjs context debugger です。
このツールを使うと、下図のように、developer tool の [Elements] – [Knockout context] タブを使って、ViewModel や、$data、$parent などの基本的な情報をモニタリングできます。(通常であれば、Debug のために、ko.toJSON($data, null, 0) のように自前で出力しなければなりません。)

さらに、上図で [KnockoutJS] タブを選択して [Enable Tracing] ボタンを押すと、上図の通り、observable の内容が変更されるたびに console に出力されます。
前述の通り、これと同じことをするには、ko.extenders を実装する必要がありますが、この extension を使うと こうしたプログラミングは不要です。(結局、この chrome extension の中で、同様のプログラミングがされています。。。)

また、Visual Studio を使用している場合、以前、Scott Hanselman が紹介していた Glimpse で、Knockout Plugin が提供されています。
こちらも、使い方は簡単です。まず、NuGet を使って、Glimpse ASP.NET と KnockoutJS inspector for Glimpse (glimpse-knockout) をインストールします。

あとは、Debug 実行をおこなって、http://<debug url>/Glimpse.axd (例えば、http://localhost:1119/Glimpse.axd など) を表示して Glimpse を On にすると、下図のように、ViewModel の状態をモニタリングできます。

 

Heavy な MVVM から Light な Binding まで幅広く使える KnockoutJS (= 導入 Risk の少ない MVx, 融通の効く MVx) ですが、周辺のさまざまなツールや Plugin も是非有効活用してみてください。

 

Comments (0)

Skip to main content