Meteor を使用したインスタント Web アプリケーション

構想から拡張デプロイメントまで、驚くほどの速さで応答性の良い Web アプリケーションを構築する

Web アプリケーション開発プラットフォームとして Meteor を使用すれば、JavaScript 開発者は極めてインタラクティブで応答性に優れたリッチ・クライアント Web アプリケーションを迅速かつ簡単に設計して構築することができます。この記事で、業界標準の JavaScript ライブラリーを利用して、Meteor によるアプリケーションを構築する実践的な経験をしてください。Sing Li が Meteor の真実に迫り、ありきたりではない機能的なサンプル・アプリケーションを通して Meteor の有望さを探ります。

編集者注: このチュートリアルは、2013年の初期ベータ版から現在のバージョンである 1.1.x に Meteor フレームワークがバージョンアップされたことによる変更内容を反映するように更新されました。

Sing Li, Consultant, Makawave

Author photoSing Li は、developerWorks サイトの開設以来、Web や Java に関するさまざまなトピックを取り上げて記事とチュートリアルを書いている developerWorks の著者です。組み込みシステムからスケーラブルなエンタープライズ・システムに至るまで、20 年を超えるシステム・エンジニアリングの経験があり、現在は再び Web 規模のモバイル対応サービスと「モノのインターネット」エコシステムに取り組んでいます。



2015年 8月 06日 (初版 2013年 7月 11日)

Web アプリケーション開発プラットフォームである Meteor は、世界中で広く採用されるようになっています。Meteor は、JavaScript のコーディング・フレームワークであるだけでなく、スケーラブルでリッチなインタラクティブ Web アプリケーションを構築する革新的な手段になります。Meteor は、開発サイクルの期間短縮を約束します。その方法は、コーディング・モデルを単純化して、開発者が作成しなければならないコードの量を削減するというものです。経験を積んだ Web アプリケーションのアーキテクトや開発者が Meteor を使用すれば、構想から完全なデプロイの完了までを数週間で行うこと、あるいは数日で行うことさえ可能です

Meteor プラットフォームをインストールして開発を開始するまでの手順を説明するガイドとしては、Meteor Web サイトのドキュメント「Quick start!」に従ってください。このチュートリアルでは、2 つのサンプル・アプリケーションの詳細を通して Meteor による開発を深く掘り下げるとともに、Meteor による Web アプリケーション開発手法の概要を紹介します。このチュートリアルで得た知識を使えば、Meteor で迅速に Web アプリケーションを作成するという方法が、自分のニーズに合った方法であるかどうかを判断することができます。

過去から現在を振り返る

Meteor で用いられる手法は、ある意味では革命的ですが、進化の結果という側面もあります。Meteor は、コンピューティングの歴史における大きな成功の 1 つである、スプレッドシート・ソフトウェアと同じ IT 路線を辿っています。典型的なスプレットシートの一例として、図 1 に地域ごとの売上高とその円グラフで構成されるスプレッドシートを示します。

図 1. 地域別売上高を示すスプレッドシート
地域別の売上高と総売上高の円グラフで構成される典型的なスプレッドシートのスクリーン・キャプチャー

クリックして大きなイメージを見る

図 1. 地域別売上高を示すスプレッドシート

地域別の売上高と総売上高の円グラフで構成される典型的なスプレッドシートのスクリーン・キャプチャー

一般的なスプレッドシートを試してみてください

図 1 のスプレッドシートは、この記事のサンプル・コードのダウンロードに含まれているので、実際に試してみることができます。売上高を変更すると、円グラフが自動的に更新されることがわかります。

地域別売上高のスプレッドシートでいずれかの地域の売上高を変更すると、円グラフが瞬時に再描画され、新しい値がスライスの相対的割合に反映されます。

こうしたスプレッドシートの機能は、今となっては目新しくはありませんが、1983年に Lotus 1-2-3 でこの機能が発表された当時のインパクトを想像してみてください。初期の PC のユーザーだったとしたら、プログラミング作業を一切せずに、これほどの成果を上げることは決してできなかったでしょう。スプレッドシート・ソフトウェアは、今でも世界的に PC の売り上げを促進するキラー・アプリの 1 つとなっています。

30 年後の今

このチュートリアルの最初のサンプル Web アプリケーション ― 図 2 に示す販売実績ポータル Web アプリケーション ― では、2015年にはこのスプレッドシートの例がどのように進化したかを Meteor でデモンストレーションします。

図 2. 販売実績ポータル Web アプリケーション
地域ごとの売上高と総売上高の円グラフを表示する、Meteor で作成した地域別売上高アプリケーションのスクリーン・キャプチャー

クリックして大きなイメージを見る

図 2. 販売実績ポータル Web アプリケーション

地域ごとの売上高と総売上高の円グラフを表示する、Meteor で作成した地域別売上高アプリケーションのスクリーン・キャプチャー

販売実績ポータルには、最新の地域別売上高と、それに対応する円グラフが表示されます。グローバル・セールス・ディレクターは、このアプリケーションを使用して売上高をモニターすることができ、各地域販売チームは、販売される都度、そのチームの売上高を更新することができます。

Meteor をインストール済みの場合、この販売実績ポータル・アプリケーションをダウンロードして、実際に使ってみることができます。それには、ダウンロードに含まれるインストール・コードを実行して作成された sales_nologin サブディレクトリーへとカレント・ディレクトリーを変更し、「meteor」と入力します。ブラウザー・インスタンスで http://localhost:3000/ にアクセスすると、地域別売上高と円グラフが表示されます (Meteor をインストールできない場合は、IBM Bluemix にホストされている Meteor を実行することができます)。任意の売上高をダブルクリックして値を変更してください。変更を確定すると、瞬時に円グラフが更新されます。複数のブラウザー・インスタンスで販売実績ポータルにアクセスしているとしたら、そのすべてのインスタンスに最新の売上高が表示され、どのブラウザー・インスタンスからでも数値を変更することができます。

図 3 では、US Central チームの売上高を選択して、その数値を更新しています。

図 3. US Central の売上高の更新
Meteor で作成された販売実績ポータル Web アプリケーションで、ユーザーが US Central 地域の売上高を選択してその数値を更新している画面のスクリーン・キャプチャー

クリックして大きなイメージを見る

図 3. US Central の売上高の更新

Meteor で作成された販売実績ポータル Web アプリケーションで、ユーザーが US Central 地域の売上高を選択してその数値を更新している画面のスクリーン・キャプチャー

図 4 に、更新後の US Central の売上高と最新の円グラフを示します。更新時には、販売実績ポータルに同時にアクセスしているユーザーのすべてに対し、瞬時に変更が表示されます。

図 4. 新しい US Central の売上高を反映して更新された円グラフの構成比率
新しい US Central の売上高を反映して更新された円グラフのスクリーン・キャプチャー

クリックして大きなイメージを見る

図 4. 新しい US Central の売上高を反映して更新された円グラフの構成比率

新しい US Central の売上高を反映して更新された円グラフのスクリーン・キャプチャー

手動による更新の代わりに、バックエンドで売上高を構成する小計が自律的に収集および集約されて、売上高が更新される場合も考えられます。販売実績ポータル・アプリケーションの視覚的表現は由緒ある昔のスプレッドシートとまったく同じですが、このアプリケーションは以下の機能も備えています。

  • 至るところで利用できるブラウザーを介した世界中からのインターネット・アクセス
  • 複数のユーザーによる同時アクセス
  • オプションの自動バックエンド・データ収集および集約

このようなシステムを標準的なエンタープライズ・テクノロジー (例えば、Java ベースのツール・チェーン) を使用して設計、コーディング、デプロイするとなると、かなりの作業が必要になります。しかし Meteor を使用することで、こうした作業が大幅に減ります。それは、この後に記載されているコードを順に見ていくとわかります。

リアクティブな考え方

この手法は、作成してデバッグおよびテストしなければならないインフラストラクチャー・コードの量を大幅に減らします。

スプレッドシートの重要な特徴の 1 つは、そのリアクティブな性質です。地域別売上高の例では、地域の売上高が更新されると、その売上高に依存するすべての値がオンザフライで再計算されます。従属コンポーネントがグラフィック出力 (例えば、円グラフ) をレンダリングする場合、そのグラフも即時に再描画されて、スライスのサイズが更新されます。依存関係を管理する (複雑になりがちな) コードや、円グラフなどのコンポーネントを更新するコードを作成する必要はありません。必要な作業は、リアクティブ要素 (売上高) とその依存関係 (この例の場合、円グラフ) を宣言することだけです。後はすべて、スプレッドシートが処理してくれます。

この手法を最近の Web アプリケーションに当てはめて考えてみると、Meteor によって Web ベースのシステムを作成するのがいかに簡単になるかを想像できます。

Meteor のリアクティブなデフォルト

Meteor には、デフォルトでリアクティブになる特定のデータ・ソースがあります。最もよく使用されているものとしては、以下のものが挙げられます。

  • Meteor コレクション — 通常は、MongoDB クエリーの結果
  • Meteor の Session シングルトンに明示的にバインドされた変数
  • Meteor.userMeteor.userId、および Meteor.logginIn (これらは、現在のユーザーおよびログインの状況を追跡します)
  • Meteor.status (サーバー接続状況を追跡します)

Meteor アプリケーションを設計するときには、まず初めにリアクティブ要素 (例えば、地域の売上高データのコレクション) を決定します。次に、標準的な HTML、CSS、クライアント・サイドの JavaScript ライブラリーとコンポーネント (jQuery、jQuery UI、または jQuery Mobile など)、Spacebars (概念は JavaServer Pages と同様ですが、通常はクライアント・サイドで動作します) などのテンプレート・テクノロジーを使用して、プレゼンテーション層をレイアウトします。Meteor はリアクティブ要素のあらゆる依存関係を追跡して、ビジュアル要素を再レンダリングし、依存関係を再計算して更新後の最新データを反映させます。

この手法は、作成してデバッグおよびテストしなければならないインフラストラクチャー・コードの量を大幅に減らします。更新リクエストを同期させるためのカスタム・バックエンド Web サービスを作成する必要がなく、データベースやデータ・ストアを更新するためのコードや、接続されたクライアントに変更通知をプッシュするためのコード、あるいは通知の受信時にバックエンドから更新後の値を取得するためのコードも、一切作成する必要はありません。


販売実績ポータルのコードの詳細

リスト 1 に、販売実績ポータル・アプリケーションの背後にあるサーバー・サイド・ロジックとクライアント・サイド・ロジックがすべて含まれた sales.js ファイルを記載します。このアプリケーションのために作成しなければならなかったのは、この JavaScript コードだけです (sales.js は、記事からコードをダウンロードしてインストールすると作成される sales_nologin ディレクトリー内にあります)。

リスト 1. 販売実績ポータルのクライアント・サイド・ロジックとサーバー・サイド・ロジック: sales.js
SalesData = new Meteor.Collection("regional_sales");
if (Meteor.isClient) {

    Template.salesdata.helpers({ 
        dataset : function () {
                    return SalesData.find({}, {sort: {row : 1}});
                  }
    });

    Template.datapoint.helpers({ 
        selected :  function () {
                        return Session.equals("selected_datapoint", this._id)
                           ? "selected" : '';
                    }
    });

    Template.title.helpers({
        thisyear:  new Date().getFullYear()
    });

Template.datapoint.events({
        'click': function (event, template) {
          Session.set("selected_datapoint", this._id);
        }
    });

    Template.piechart.helpers({
     'plotchart' : function() {
       plotit(this, SalesData.find({}));
     }
    });

    function plotit(inst,cur)  {

     if (cur.count() === 0)  // do not render pie if no data
           return;
         var data = [];
         cur.forEach( function(sale) {
           data.push( [sale.region, sale.total]);
         });
      window.$.jqplot('chart', [data], 
        { 
          seriesDefaults: {
            // Make this a pie chart.
            renderer: $.jqplot.PieRenderer, 
            rendererOptions: {
              // Put data labels on the pie slices.
              // By default, labels show the percentage of the slice.
              showDataLabels: true
            }
          }, 
          legend: { show:true, location: 'e' }
        }
      );   

    }

    Template.datapoint.onRendered(function()
    {
       this.$('.editable').editable( {
         autotext: 'never',
         type: 'text',
         width: 10,
         mode: 'inline',
         success:    
          if (newvalue != "") {
            var testint = Number(newvalue);
            if (Math.floor(testint) == newvalue) {
           SalesData.update(Session.get("selected_datapoint"), {$set: {total: parseInt(newvalue)}});
          } else {
           return ({newValue: $(this).text()}); 
          }
        } else {
          return ({newValue: $(this).text()});
        },
      display: function() {
       // dummy display function so 'text' is not set, Blaze will set it
      }
      });
});
} // if isClient

if (Meteor.isServer) {
  Meteor.startup(function () {
   if  ((process.env['CLEARDATA']) || (SalesData.find().count() == 0)) {
      var roworder = 0; 
      SalesData.remove({});
      SalesData.insert({region:"US East", total: 2032333, row: roworder++});
      SalesData.insert({region:"US Central", total: 150332, row: roworder++});
      SalesData.insert({region:"US West", total: 1202412, row: roworder++});
      SalesData.insert({region:"Asia Pacific", total: 701223, row: roworder});
  }  
                  
  });

}

Meteor.isClient 変数と Meteor.isServer 変数に関する条件文は、Meteor のコアによって提供されるランタイム・コンテキスト・インディケーターであり、コード内のどこからでも使用することができます。この例では、これらの条件文により、同じ sales.js ファイル内でクライアント・サイドのコードとサーバー・サイドのコードを組み合わせて使用できるようにしています。条件文の外側にあるコードはすべて、クライアントとサーバーの両方で実行されます。

別の方法として、クライアントのためのコードを client という名前のサブディレクトリーに置き、サーバー・サイドのコードを server という名前のサブディレクトリーに置くことで、クライアントとサーバーのソース・コードを分離することもできます。そのシナリオでは、クライアントのためのアセット (画像など) を public というサブディレクトリーに配置します。特定のリソースをサーバーからのアクセスでのみ使用できるように (その特定のリソースは、クライアントに対しては提供しないように) 制限するには、それらのリソースを private という名前のサブディレクトリーに配置します。(このチュートリアルで後ほど扱うことになる写真共有アプリケーションでは、今説明したディレクトリー構造を使用しています。)

リアクティブなデータを識別する

リスト 1selected_datapoint セッション変数はリアクティブです (デフォルトでリアクティブな要素については、囲み記事「Meteor のリアクティブなデフォルト」を参照)。この変数は、強調表示されている売上高の行が変更された場合に使用されます。行の強調表示は、動的 CSS スタイルの変更によって行われます。selected_datapoint セッション変数は、ユーザーが行をクリックすると更新されます。この変数が変更されるたびに Meteor は依存関係を再レンダリングするため、強調表示もそれに応じて更新されます。selected_datapoint は、クライアント・サイドにのみ存在することに注意してください。

販売実績ポータル・アプリケーションのもう 1 つのリアクティブ・データ・ソースは、SalesData という Meteor コレクションに対するクエリーです。selected_datapoint とは違って、SalesData はクライアントとサーバーの両方に存在し、サーバーでは SalesData は MongoDB コレクションです。SalesData の使用方法は、リスト 1 で確認することができます。

このクエリーはリアクティブであるため、その依存関係のすべては、クエリーの結果セットが変わると再計算または再レンダリングされます。このようにして、すべてのブラウザー・インスタンスにわたって売上高と円グラフが更新されます。リスト 2 に、関連する HTML テンプレート・コードを記載します。このコードは、記事からコードをダウンロードしてインストールすると作成される sales_nologin ディレクトリー内にある sales.html ファイルに含まれています。

リスト 2. クライアント・サイドの HTML およびテンプレート: sales.html
<template name="salesdata">
  <div class="salesdata">
    {{#if Template.subscriptionsReady}}
      {{#each dataset}}
        {{> datapoint}}
      {{/each}}
    {{/if}}
  </div>
</template>

<template name="datapoint">
  <div class="datapoint {{selected}}">
    <div id="{{_id}}_region" class="region">{{region}}</div>
    <div id="{{_id}}_total" data-inputclass="inputclass" class="sales editable">{{total}}</div>
  </div>
</template>

リスト 2 の HTML ファイルは、Spacebars テンプレートです。Spacebars は Meteor 独自のテンプレート・エンジンです。ご覧のように、リスト 2 では Spacebars の式は二重波括弧 {{ }} で囲まれています。(Meteor には、Meteor のレンダリング・システム Blaze を通じて、他の JavaScript テンプレート・エンジンと連携できる可能性もあります。)

売上高の行は、リスト 2 に示す salesdata テンプレート・コードによってレンダリングされます。このテンプレートは dataset ヘルパー関数 (リスト 1 を参照) に依存するため、その内側にあるリアクティブ・クエリーが変更されるたびに再レンダリングされます。

サーバーにサンプル・データを投入する

販売実績ポータルの地域売上高の初期データは、リスト 3 に記載するサーバー・サイドのコード (リスト 1 からの抜粋) によって投入されます。

リスト 3. MongoDB にデータを投入するサーバー・サイドのコード
 SalesData.remove({});
 SalesData.insert({region:"US East", total: 2032333, row: roworder++});
 SalesData.insert({region:"US Central", total: 150332, row: roworder++});
 SalesData.insert({region:"US West", total: 1202412, row: roworder++});
 SalesData.insert({region:"Asia Pacific", total: 701223, row: roworder});

Meteor での遅延補償

Meteor の「遅延補償 (latency compensation)」とは、ビッグ・データ管理における「結果整合性」の概念のビジュアル・バージョンです。Minimongo エミュレーターによってクライアント上でデータを更新すると、クライアント上では即時にすべての変更が反映されます (これにはリアクティブ再レンダリングも含まれます)。変更はサーバーにも伝播されますが、伝播された変更はさまざまな理由 (アクセス拒否を含む) で正しく適用されない可能性があります。最終的に (通常はすぐに) サーバーの状態がクライアントに反映されることを確実にするのは、パブリッシュ・サブスクライブ・メカニズムですが、遅延補償は、最近の Web アプリケーションの特質である、遅延のない極めて応答性の良い UI を可能にします。ただし、その代償として、ビジュアル・データの整合性が一瞬失われる可能性があります。

Meteor サーバー上では、完全な MongoDB インスタンスが稼働中になります (この完全なインスタンスは、Meteor 以外のクライアントからのクエリーと更新を受け付けることができます)。クライアント・サイドでも、同じ JavaScript MongoDB API が使用できることから、クライアントとサーバーのコードが 1 つに統合されて、クライアントとサーバーの両方でコードを再利用できるようになります。クライアント・サイドの API は、Minimongo という名前の Mongo エミュレーターによって提供されます。Minimongo は遅延補償を使用してデータベースの変更を反映します。Minimongo が扱うのは一般にクライアント・サイドの小さなデータ・セットであるため、Minimongo は索引付けをサポートしていません。

MongoDB サーバーと Minimongo クライアントの間で同期されるデータの制御には、非同期のパブリッシュ/サブスクライブ・モデルが使用されます。デフォルトでは、サーバー・サイドのすべての Meteor コレクションがパブリッシュされます。Meteor は DDP (Distributed Data Protocol) を使用して、クライアントとサーバーとの間でデータを移動します (他のデータベースには、クライアント・サイドのエミュレーターとサーバー・サイドのスタブという形で DDP ドライバーを作成することができます。Meteor コミュニティーでは、PostgreSQL ドライバーと RethinkDB ドライバーに関する作業が現在進行中です)。

jQuery のプラグインを統合する

販売実績ポータルで円グラフをレンダリングするために使用しているのは、jqPlot という jQuery のプラグインです。円グラフのレンダリングと再レンダリングは、SalesData コレクションに含まれるデータの変更に反応して行われます。すでに説明したように、SalesData コレクションに変更があるたびに salesdata テンプレートが再レンダリングされます。salesdata テンプレートの rendered イベントがトリガーされると、リスト 4 に記載するクライアント・サイドの関数 (リスト 1 からの抜粋) が円グラフを再レンダリングします。

リスト 4. jqPlot プラグインを使用して円グラフをレンダリングする jQuery コード
window.$.jqplot('chart', [data], 
     { 
       seriesDefaults: {
         // Make this a pie chart.
         renderer: $.jqplot.PieRenderer, 
         rendererOptions: {
           // Put data labels on the pie slices.
           // By default, labels show the percentage of the slice.
           showDataLabels: true
         }
       }, 
        legend: { show:true, location: 'e' }
     }
   );

売上高のインプレース編集を可能にするために、販売実績ポータルでは x-deitable という jQuery のプラグインを使用しています。編集を処理するコードは、リスト 1Template.datapoint.onRendered() ハンドラーの中にあります。


販売実績ポータルへのアクセスに対するセキュリティーの強化

Meteor でサポートされているデフォルトのプロトタイプ・モードは、初期段階でアプリケーションを素早く進化させるには理想的です。初期段階では、対話部分、UI、さらにはアプリケーション・ロジックでさえも、短期間で何度も変更することになるかもしれませんが、通常、この段階では機密性のあるデータが関わってくることはありません。このプロトタイプ・モードでは、共同で作業する開発者やレビューを行うユーザーと URL を共有して、フィードバックを収集することができますが、この販売実績ポータルの URL を知っている人であれば、誰でも売上高のデータを見ることや、データを変更することさえできてしまいます。このオープン・アクセス・モデルは、本番で使用するには寛大すぎます。

初期段階の次に来る当然のステップは、Meteor のセキュリティー機能を有効にしてアプリケーションをロック・ダウンすることです。よりセキュアなバージョンの販売実績ポータルのコードは、記事からコードをダウンロードしてインストールすると作成される sales サブディレクトリー内にあります。このコードには、以下のセキュリティー機能が追加されています。

Meteor のパッケージ

Meteor のパッケージは、meteor add コマンドによって簡単に、Meteor に対して追加や削除を行える機能モジュールです。Meteor のパッケージには、サーバー・サイドのコード、クライアント・サイドのコード、スタイルシート、UI、API などを含めることができます。このチュートリアルでは accounts-uiautopublish、および insecure の例を紹介しますが、Meteor のパッケージを追加することによって、CoffeeScript のサポートや URI ルーティングをはじめとするさまざまな機能を追加することもできます。Atmosphere リポジトリーには、Meteor のコミュニティーによって作成された何千というパッケージがあり、これらのパッケージは自分のアプリケーションに追加することができます。

  • 許可されたユーザーだけにポータルへのアクセスを許可するためのユーザー認証システム
  • 地域の売上高データの正式所有者だけにデータの変更を許可するコード
  • デプロイされたクライアントに対し、機密の可能性があるサーバー・サイドのコードが決して提供されることがないように改善されたソース・コード編成

これ以降で参照する販売実績ポータル・アプリケーションは、いずれも sales ディレクリー内にあるセキュア・バージョンとなります。

クライアントからサーバー・データを変更できないようにする

アプリケーションをロック・ダウンするための出発点としてふさわしいのは、誰もデータを変更することができないようにすることです。以下のコマンドを使用して insecure パッケージを削除するだけで、この目的を果たすことができます。

insecure パッケージは、サーバーに対し、データの読み取りや変更の際にアクセス・ルールをチェックしないように指示します。このパッケージはデフォルトでインストールされるため、すべてのアクセスが許可されますが、これを削除した後は、クライアントはサーバー・データを変更できなくなります。ブラウザー・インスタンスのいずれかに戻り、売上高データを変更しみてください。すると、アプリケーションがデータを変更しようとしても、サーバーからのアクセス拒否を反映して、すぐにデータが元の状態に戻ります (これは遅延補償が実際に動作している 1 つの例であり、データは実際にはクライアントで一瞬更新されますが、サーバーからの正式なコピーが到着した時点で、クライントのデータが上書きされます)。

insecure パッケージを削除した後は、特定のデータへの (特定のユーザーによる) アクセスを明示的に許可するためのアクセス・ルールを追加する必要がありますが、まだユーザーは存在していません。そこで次に必要となる作業は、ユーザー・データベースとログイン許可システムを追加することです。

許可されたユーザーだけに売上高データの表示を許可する

ユーザー許可システムを追加する前に、誰にも売上高データを見られないようにする必要があります (許可されるユーザーについては、後でデータを表示できるように処理します)。今のところ、ユーザーがデータを変更することはできませんが、販売実績ポータルの URL にアクセスすると、誰でもデータを表示することができます。

Meteor のコレクション・データ (サーバーが明示的にパブリッシュするデータや、クライアントがサブスクライブするデータを除く) がサーバーからクライアントにプッシュされないようにするには、デフォルトでインストールされる autopublish パッケージを以下のようにして削除します。

meteor remove autopublish

このコマンドを実行した後に販売実績ポータルの URL にアクセスすると、地域別売上高データと円グラフは表示されなくなっているはずです。

accounts パッケージを使用してユーザー・ログインを追加する

Meteor には、ユーザー・ログインおよびアクセス許可システムを容易に追加できるようにするパッケージが用意されています。エンドツーエンドのワークフローをカバーする accounts-ui パッケージと accounts-password パッケージには、必要となるフロントエンドの UI、バックエンド・データベース、そしてクライアント・サーバー間の API が揃っています。これらの機能のすべてを、たった 1 つのコマンドで販売実績ポータルに追加することができます。

meteor add accounts-password accounts-ui

account-password パッケージは、ユーザーの作成と、e-メール・アドレスとパスワードによるログインをサポートします。このパッケージの実装では、SRP (Secure Remote Password) プロトコルを使用するため、クライアントとサーバーとの間で平文のパスワードが送信されることは決してありません。

パスワード・ベースのログインに加え、1 つ以上のパッケージをアプリケーションに追加するだけで、Facebook、Twitter、Weibo、GitHub、および Google からユーザーがサインインできるようにすることも可能です。(ソーシャル・ネットワークが OAuth ログインをサポートすると、一般コンシューマー向けのアプリケーションにとっては価値がありますが、企業のイントラネット環境においては適用性が限られてしまうかもしれません。)

ユーザー・ログイン UI のカスタマイズ

UI ウィジェットで使用するダイアログ・ボックスのスタイル設定をより柔軟に制御したい場合は、accounts-ui パッケージの代わりに accounts-ui-unstyled パッケージを追加してください。UI の制御を完全に引き継ぎたいとしたら、このプロセスで使用する API とデータ・フローについての説明を Meteor のドキュメントで調べてください。

ログイン用の UI を追加する

accounts-ui パッケージには、ユーザーのログイン処理、新規ユーザーの作成処理、およびパスワードを忘れた場合のリカバリー処理のために事前に作成された CSS スタイルの UI ウィジェット一式 (そして、それらをサポートする JavaScript コード) が提供されています。これらのウィジェットを追加するには、{{>loginButtons}} Spacebars テンプレートを追加します。リスト 5 に、販売実績ポータル・アプリケーションに追加したログインを示します (sales/sales.html ファイルから抜粋したコードです)。

リスト 5. ユーザー・ログインおよびアクセス許可システムを追加する
<body>
<div id="title">
   <div>
        {{> title }}
   </div>
   <div> 
       <div style="float: right">
       {{> loginButtons align="right"}} 
     </div>
   </div>
   </div>
  </div>

記事からサンプル・コードをダウンロードしてインストールすると作成される sales ディレクトリーに、ユーザー・アクセス制御を追加した完全な販売実績ポータル・アプリケーションが格納されています。このバージョン (または Bluemix にホストされているバージョン) を実行して、ログインしてみてください。ブラウザー・インスタンスを開始すると、右上隅に「Sign in (サインイン)」リンクが表示されます。このリンクをクリックすると、図 5 に示すダイアログ・ボックスが表示されるはずです。

図 5. accounts-ui パッケージに含まれるサインイン・ダイアログ・ボックス (Firefox で表示)
ブラウザー (Firefox) に表示されたサインイン・ダイアログ・ボックスのスクリーン・キャプチャー

クリックして大きなイメージを見る

図 5. accounts-ui パッケージに含まれるサインイン・ダイアログ・ボックス (Firefox で表示)

ブラウザー (Firefox) に表示されたサインイン・ダイアログ・ボックスのスクリーン・キャプチャー

accounts-ui パッケージがユーザー・データベースを実装するために使用するのは、Meteor のコレクションとパブリッシュ・サブスクライブです (独自に作成したコードでも使用できる機能です)。販売実績ポータルの現在のバージョンでは、データベースにユーザー・クレデンシャルのセットを 2 つ (joe@dwtestonly.com / abc123 と sing@dwtestonly.com / abc123) 作成してあります。2 つのブラウザー・インスタンスを開いて、それぞれのクレデンシャルを使ってログインしてください。

追加のユーザーを作成するには、「Sign in (サインイン)」ダイアログ・ボックスの「Create account (アカウントの作成)」リンクをクリックします。図 6 に、accounts-ui パッケージに含まれる新規ユーザー作成ダイアログ・ボックスを示します。

図 6. accounts-ui パッケージに含まれる新規ユーザー・アカウントを作成するためのダイアログ・ボックス (Chrome で表示)
ブラウザー (Chrome) に表示された、新規ユーザーを作成するためのダイアログ・ボックスのスクリーン・キャプチャー

クリックして大きなイメージを見る

図 6. accounts-ui パッケージに含まれる新規ユーザー・アカウントを作成するためのダイアログ・ボックス (Chrome で表示)

ブラウザー (Chrome) に表示された、新規ユーザーを作成するためのダイアログ・ボックスのスクリーン・キャプチャー

地域別売上高データに所有者のフィールドを追加する

販売実績ポータルの現在のバージョンでは、初期データベースの内容が変更されています。リスト 6 に、データを投入するために使用したサーバー・サイドのコードを記載します。

リスト 6. サーバー・サイドのデータ投入コード
SalesData.remove({});
SalesData.insert({region:"US East", total: 2032333, row: roworder++});
SalesData.insert({region:"US Central", total: 150332,  row: roworder++, owner: joeid});
SalesData.insert({region:"US West", total: 1202412, row: roworder++});
SalesData.insert({region:"Asia Pacific", total: 701223, row: roworder});

リスト 6 のコードには、新規の owner フィールドが追加されています。この例で owner フィールドに格納されるのは、US Central 地域のデータを所有するユーザー (joe@dwtestonly.com) のユーザー ID です。このフィールドを使用して、地域別売上高データの更新を joe@dwtestonly.com だけに許可します。ユーザー ID の値は、Meteor.users コレクションに対してクエリーを実行することで取得できます。

サーバー・データをきめ細かく選択してパブリッシュする

autopublish パッケージが削除されているので、サーバーから明示的にデータをパブリッシュして、クライアントからもそのデータを明示的にサブスクライブする必要があります。

販売実績ポータルの場合、サーバーはリスト 7 に記載するコード (sales/server/sales.js ファイルから抜粋) を使用して regional_sales コレクションをパブリッシュします。

リスト 7. サーバーから選択的にデータをパブリッシュする
Meteor.publish("regional_sales", function () {
      if (this.userId) {  // only visible to logged in users
      // do not include the owner field for client access
      return SalesData.find({}, {fields: {"region": 1, "total":1 }}); 
      }
});

リスト 7 で注目する点は、有効なユーザーがクライアント・サイドのセッションにログインしていることを確実にするために使用している this.userId です。Meteor がユーザーに代わってサーバー・コードを実行するときには、常に this.userId に、現在ログインしているユーザーの一意の ID が格納されます。現行のブラウザー・インスタンスにログインしているユーザーがいない場合、this.userId は null となり、データはパブリッシュされません。さらに、リスト 7 では、地域別売上高データ文書 (基本的に、MongoDB インスタンスの可変数のフィールドからなるレコードの文書) のすべてのフィールドが、クライアントに送信されるコレクションで返されるわけではありません。具体的に言うと、この文書の owner フィールドはクライアントに対して隠されます。この仕組みにより、クエリーを使用して、フィールドのサブセットを含めたコレクションのサブセットのみを、許可されたユーザーがログインしているクライアントのみに送信することが可能になります。この手法は、クライアント・ブラウザーが特定の文書の機密データのフィールドにアクセスできないようにする場合に役立ちます。

クライアント・サイドでデータをサブスクライブする

販売実績ポータルのクライアント・コードは、サーバーがパブリッシュする regional_sales コレクションを明示的にサブスクライブします (リスト 8 を参照)。Meteor は、テンプレート・インスタンス単位でのサブスクライブをサポートします。テンプレート単位でのサブスライブを使用することで、テンプレート・インスタンスによってレンダリングされたデータのみがプッシュされるようになると同時に、テンプレート・インスタンスが破棄されたときにサブスクライブが正しく削除されるようにもなります。

リスト 8. サーバーからのコレクションに対してテンプレート単位でサブスクライブするクライアント
Template.piechart.onCreated(function() {
  this.subscribe("regional_sales");
});

Template.salesdata.onCreated(function() {
  this.subscribe("regional_sales");
});

地域別売上高データの更新を許可するためのアクセス・ルールを追加する

insecure パッケージが削除された状態では、事実上すべてのユーザーが、売上高データの更新操作を拒否されます。それぞれの地域別売上高を所有しているのが異なるユーザーであるとしたら、アクセス・ルールを追加することで、joe@dwtestonly.com による US Central データの更新を許可することができます。そのアクセス・ルールは、リスト 9 のとおりです。これは、model.js という名前のサーバー・サイドのソース・ファイルに含まれています。

リスト 9. 所有者に売上高の更新を許可するためのサーバー・サイドのアクセス・ルール
SalesData.allow({
  update: function (userId, sales, fields, modifier) {
    if (userId !== sales.owner)
      return false; // not the owner

    var allowed = ["total"];
    if (_.difference(fields, allowed).length)
      return false; // tried to write to forbidden field

    return true;
  },

});

update 操作に対するアクセス・ルール関数は、更新が許可される場合は true を返し、許可されない場合は false を返します。リスト 9 のコードによって、ユーザーが所有者であることと、total フィールドだけが変更されることが確実になります。

反復型開発のための Meteor のホット・コード・リロード

開発とデバッグの時間を節約するには、コード、CSS、あるいはテンプレートを変更している最中でも、ブラウザーが Meteor アプリケーションにアクセスしている状態を維持してください。Meteor のホット・コード・リロード機能は変更を検出し、その変更をクライアント・ブラウザーにプッシュします。

販売実績ポータルを開いて joe@dwtestonly.com としてログインし、US West のデータを変更してみてください。変更できないことを確認した後、US Central のデータを変更してみます。joe@dwtestonly.com はこのデータの所有者であるため、データの更新に成功します。

別のブラウザー・インスタンスを立ち上げて、今度は sing@dwtestonly.com としてログインします。売上高データのいずれかを変更しようとすると、その操作はできません。sing@dwtestonly.com が所有する売上高データは 1 つもないため、サーバーはこのユーザーからの変更リクエストはすべて拒否します。

ユーザーがログインしていない場合に、テンプレートがレンダリングされないようにするには、クライアント・サイドの currentUser ヘルパーを使用することができます。リスト 10 に記載するコードを HTML ファイルに追加してください。

リスト 10. 空のテンプレートのレンダリングの試行を排除する
<div id="container">
    <div id="salestable">
      {{#if currentUser}}
          {{> salesdata}}
      {{/if}}
    </div>
   <div>
      {{#if currentUser}}
           {{> piechart}} 
       {{/if}}
        </div>
</div>

上記のコードを追加した上で、新しい販売実績ポータル・ブラウザー・インスタンスを立ち上げると、データは表示されません。sing@dwtestonly.com としてログインすると、データと円グラフが表示されます。次は、フィールドを変更してみてください。所有者ではないため、フィールドを変更できないはずです。

さらに別のブラウザー・インスタンスを立ち上げて、joe@dwtestonly.com としてログインすると、データが表示されます。US Central の数値を変更すると、円グラフが更新されます。sing@dwtestonly.com セッションでの円グラフも変更されていることを確認してください。2 つのセッションからサインアウトして、データが非表示になることを確認してください。


クラウドでのアプリケーションのデプロイ

Meteor アプリケーションを Bluemix にデプロイするのは簡単です。以下に記載する私のスクリーンキャストの手順に従ってください。

見る:Deploy meteor apps on Bluemix

組み込みの Meteor コマンドを使用して、アプリケーションをクラウドにホストされている Meteor のサーバーにデプロイすることもできます。このチュートリアルを作成している時点では、このサービスは無料で利用することができます。このサービスを利用するには、自分のアプリケーションのディレクトリーから以下のコマンドを実行します。

meteor deploy applicationname.meteor.com

アプリケーション名は一意でなければなりません。この名前が http://<アプリケーション名>.meteor.com として (インターネットで世界に) 公開されるためです。アプリケーションを初めてデプロイする際には、meteor.com にアカウントを作成するよう促されます。

このチュートリアルを作成している時点で、Meteor チームは Galaxy という新製品に取り組んでいます。Galaxy は、Docker コンテナーの Kubernetes オーケストレーションをベースにした、スケーラブルなデプロイメント・プラットフォームです。

独自のサーバー・インフラストラクチャーでアプリケーションをホストする場合、Node.js と MongoDB 機能をインストール済みのサーバーが必要です。アプリケーションのデプロイ可能なバンドルを作成するには、以下のコマンドを使用します。

meteor build  directory to place deployable bundle

Node.js でのファイバー

ファイバーは、個々の論理フロー (ファイバー) 間でのノンプリエンプティブ・マルチタスクを可能にします。つまり、あるファイバーが明示的に実行を譲ってからでないと、別のファイバーが実行を開始することはできません。実行を譲るポイントは正確に制御できることから、通常はファイバー間で共有される状態を保護する必要はありません。ファイバーの重要な機能は、表記に利便性がもたらされることです。Node.js のプログラミングに典型的な深くネストされたコールバックを作成する代わりに、シーケンシャルに見えるコード (論理フローごとに 1 つのスレッドなど) を作成することができます。

サーバー・サイドでデプロイ可能なのは Node.js アプリケーションであることから、独自の相互運用要件やスケーリング要件に合わせてデプロイメント・トポロジーをカスタマイズすることができます。

Meteor のサーバー・サイドのコードは、Node.js ファイバーで実行されます (囲み記事「Node.js でのファイバー」を参照)。これにより提供される仮想環境では、着信するリクエストごとに 1 つのスレッドが処理を行っているかのような (共有可能な状態がない) コードを作成することができます。この手法では、サーバー・サイドの JavaScript ロジックのコーディングが簡単なものになります。


Foto Share: モバイル写真共有サービス

少量の Meteor コードを伴うわずかな設計および計画作業によって、どの程度のことができるかを理解した今、読者の皆さんは、すでに新しいプロジェクトの 1 つや 2 つを思い付いているかもしれません。次のサンプルでは、モバイル機器向けの Meteor アプリケーションを作成する際にさらに適用しなければならない考え方を紹介します。

Meteor とモバイル・アプリ

Meteor は 1.0 リリース以降、Android 端末や iOS 端末向けのモバイル・アプリの作成をサポートしています。

競争力のあるモバイル・アプリを設計するには、端末上で実行可能なコードをコンパイルできる基本機能を遥かに超える機能 (つまり、Meteor の Isobuild ツールが提供する機能) が必要になります。また、優れたモバイル・アプリには、以下のことが求められます。

  • インターネットに接続していないときでも使用できること
  • ユーザーがアプリにアクセスする度にログインを要求しないこと
  • 端末ネイティブのルック・アンド・フィールであること
  • いつでも一時中断することや割り込むことができ、後で再開できること
  • リッチな通知機能、クラウド同期機能、フォト・ギャラリー、連絡先、ソーシャル・ネットワークなど、プラットフォームのデファクト機能との緊密な統合をサポートすること

こうした要求事項には、端末のネイティブ API を呼び出せる Apache Cordova の機能を使用したカスタム・コードで対処することができますが、そこまで対処することは現在の Meteor リリース (そして、このチュートリアル) の範囲を超えています。ここで紹介する Foto Share アプリは、モバイル端末上で使用可能な Meteor Web アプリです。

Foto Share は、携帯電話ユーザー向けの Web ベースの写真共有サービスの概念実証です。ユーザーは携帯電話で自分たちの写真のコレクションをブラウズしたり、「Share (共有)」ボタンをタップすることで写真を友達と共有したりすることができます。図 7 に、Apple iPhone で実行中の Foto Share を示します。

図 7. Apple iPhone で実行中の Foto Share
Apple iPhone で実行中の Foto Share のスクリーン・キャプチャー

販売実績ポータル・プロジェクトと同じセキュリティー上の理由から、Foto Share でも autopublishinsecure の 2 つのパッケージは削除されています。また、同じくパスワード・ベースのログインを実装するために、Foto Share にも accounts-uiaccounts-password の 2 つのパッケージが追加されています。記事に付属のコードのダウンロードに含まれる Foto Share アプリには、販売実績ポータルと同じ 2 人のユーザーが設定されています。

Foto Share を試すには、まず、記事からコードをダウンロードしてインストールすると作成される fotoshare ディレクトリーからアプリを実行します (Meteor をインストールしていない場合は、Bluemix にホストされているバージョンを実行することができます)。携帯電話が 2 台ある場合は、それぞれのブラウザーで Foto Share にアクセスしてください。携帯電話が使えない場合は、引き続き PC のブラウザーを使用して構いません。一方のブラウザー・インスタンスでは sing@dwtestonly.com としてサインインし、もう一方では joe@dwtestonly.com としてサインインします (販売実績ポータルで使用したのと同じパスワードを使用します)。Sing の写真をブラウズするには、写真をスワイプするか、左右いずれかのオーバーレイにタッチします。新しく表示される写真は、ビューにスライドインします。Sing の写真はすべてハワイの風景であり、Joe の写真はアステカとマヤの遺跡であることがわかるはずです。

共有機能をテストする準備ができたら、Joe としてサインインした携帯電話の写真コレクションの中から 1 枚を選択し、「Share (共有)」ボタンにタッチします。Sing としてサインインした携帯電話では、この操作に反応し、サブスクライブの対象であるコレクションを Meteor が更新します。これによって、Joe が共有する写真が Sing としてサインインした携帯電話上でも表示できるようになります。

Foto Share ユーザー・ログイン UI

Meteor による Web アプリケーションの場合と同じように、カスタマイズ可能なモバイル・ログイン UI を投入できるようになったら最高でしょうが、Meteor には (まだ) モバイル対応の accounts-ui パッケージがありません。とりあえず、Foto Share には accounts-ui Web UI を使用しました。図 8 に、携帯電話に表示されたログイン・ダイアログ・ボックスを示します。

図 8. Foto Share のログイン画面
携帯電話に表示された Foto Share ログイン画面のスクリーン・キャプチャー

Foto Share のリアクティブ・データを識別する

概念的に、当然リアクティブにするべきデータ・コレクションは、ユーザーの一連の写真です。こうすることで、ユーザーが自分の写真を共有すると常に Meteor が写真のリストを更新して再レンダリングできるようになります。これが、この概念検証で採用している手法です。大規模なシステムの場合、画像のバックエンド・ストレージ・アーキテクチャーによっては、画像そのものではなく、写真のメタデータだけをリアクティブにすることをお勧めします。

リスト 11 に記載するサーバー・サイドのデータ投入コードを見て、写真がどのように保管されるのかを把握してください。

リスト 11. Foto Share サーバー・サイドのデータを投入してコレクションをパブリッシュするコード
Meteor.startup(function () {
      
      ...     
      
      Fotos.remove({});
      Fotos.insert({name:"pic1", img: readPic('pic1.jpg'),
       owner: sing._id, shared:false});
      Fotos.insert({name:"pic2", img: readPic('pic2.jpg'),
       owner: sing._id, shared:false});
      Fotos.insert({name:"pic3", img: readPic('pic3.jpg'),
       owner: sing._id, shared:false});
      Fotos.insert({name:"pic4", img: readPic('pic4.jpg'),
       owner: joe._id, shared:false});
      Fotos.insert({name:"pic5", img: readPic('pic5.jpg'),
       owner: joe._id, shared:false});
      Fotos.insert({name:"pic6", img: readPic('pic6.jpg'),
       owner: joe._id, shared:false});

    Meteor.publish("photos", function () {
      if (this.userId) {  // only visible to logged in users
       return Fotos.find( {$or : [{owner: this.userId}, {shared: true}]},
  {fields: {"name": 1, "img":1 , "owner": 1}}); 
      }

  });
});

サーバーがパブリッシュするコレクションは Fotos です。Fotos に含まれるそれぞれの文書が写真を表します。これらの文書ごとに、nameimgowner の各フィールドがあります。img フィールドは、ローカルに保管された対応する JPG ファイルから読み取られます。この場合も、サブスクライブしているクライアントが受信するデータに含まれるのは、そのユーザーが所有する写真に加え、所有者によって共有されている他の写真だけです。さらに、ここでも選択的フィールド・フィルタリングを使用して、クライアントが受信する Foto コレクションから shared フィールドを削除しています。owner フィールドは、フィルタリングによって除外されません。これは、クライアントが共有されている写真の所有者の名前を表示できるようにするためです。リスト 12 に、readPic() ヘルパー関数を記載します。この関数は、Meteor の Assets.getBinary() ヘルパーを使用して画像をメモリーに読み込んでから、バイナリー・ストリームを base64 にエンコードして img フィールドに格納します。このフォーマットは、クライアント・サイドで写真が取得されたときに、その写真を表示するのに役立ちます。Assets パッケージを使用すると、private サブディレクトリーの下にあって、サーバーでのみ使用できるリソースにアクセスすることができます。

リスト 12. MongoDB ストレージの JPG 画像を読み取るヘルパー関数
function readPic(infile)  {       
      var data = Assets.getBinary('images/' + infile);
      var buf =  new Buffer(data);
      var tp = buf.toString('base64');
      return  'data:image/jpeg;base64,' + tp;       
  }

データベースから画像が再構成される際には、最近のほとんどのブラウザーでは、テンプレート・コードが <img> タグ内の data URL サポートを利用します。<img> タグの src 属性での data URL サポートにより、base64 にエンコードされたストリングから画像のバイナリー・ビットを動的に設定することができます。リスト 13 に、photoitem テンプレートを示します。このテンプレートでは、base64 にエンコードされた写真の img フィールドを使用して、画像をレンダリングします。

リスト 13. data URL を使用して img タグの src 属性を設定する
<template name="photoitem">
  <div class="m-item">
       <img id="{{_id}}" src="{{img}}" />
  </div>
</template>

Meteor のリモート・メソッド: カスタム RPC の単純化

Insecure パッケージは削除されていますが、Foto Share のアクセス・ルールはまだ作成されていません。アクセス・ルールがなければ、クライアントが Minimongo によってデータを更新することはできません。けれども、「Share (共有)」ボタンがタップされたときに、何らかの方法で写真の share フィールドが更新されるようにする必要があります。その方法とは何かと言うと、それは Meteor のリモート・メソッドです。

Meteor のリモート・メソッドとは、リモート・プロシージャー・コール (RPC) メカニズムのことです。クライアントからサーバーへの RPC 呼び出しは、2 つのステップで作成することができます。

  1. サーバー・サイドで JavaScript 関数を定義する
  2. Meteor.call() を使用して、そのサーバー関数をリモートで呼び出し、オプションでいくつかの引数とコールバック関数を渡します。

エンドポイントのセットアップ、セットアップ解除、そしてその間のデータ・マーシャリングといった雑事はすべて Meteor が処理してくれます。

ユーザーが Foto Share で「Share (共有)」ボタンをタップすると、クライアントがサーバー上の shareThisPhoto という Meteor リモート・メソッドを呼び出して、写真の ID を引数として渡します。サーバー・サイドでは、このコードは最初に呼び出し側が写真の所有者であるかどうかをチェックし、所有者がメソッドを呼び出した場合にだけ写真の shared フィールドを更新します。リスト 14 に、サーバー・サイドの shareThisPhoto コードを記載します。

リスト 14. 写真の shared フィールドを更新するサーバー・サイドの Meteor リモート・メソッド
Meteor.methods({
  shareThisPhoto: function (photoId) {
var curPhoto = Fotos.findOne({_id: photoId});
    if (this.userId !== curPhoto.owner)  {
      return "Cannot share this photo.";
    } else {
      Fotos.update({_id: photoId}, {$set :{shared: true}});
      return "Photo shared!";
    }

  },
});

ユーザーが「Share (共有)」ボタンをタップしたときにリモート・メソッドを呼び出すクライアント・サイドのコードは、リスト 15 のとおりです。

リスト 15. 「Share (共有)」ボタンがタップされるとリモート・メソッドを呼び出すクライアント・サイドのコード
Template.photopage.events({
  'click .fs-logoff': function () {
    Meteor.logout(function() {

      location.reload();
    });
  },
  
  'click .fs-share': function() {
      var curselected = $('.m-active > img').attr('id');

      Meteor.call('shareThisPhoto', curselected, function (error, retval) {
 console.log(retval);
      });
  }
});

ここでは Meteor リモート・メソッドを説明するために RPC 手法を選びましたが、所有者に shared フィールドの更新を許可するアクセス・ルールを定義するという手法もあります。その場合、ユーザーが「Share (共有)」ボタンをタップしたときに、写真の shared フィールドをローカルで更新する必要があります。その更新は、Meteor の Minimongo によってサーバーにプッシュされた後、サブスクライブしている他のすべてのクライアントにプッシュされます。


今どきの Web アプリケーションを構築するためのプラットフォーム

非同期データ更新ストリーム

サブスクライブされているデータの変更は、DDP を介して非同期でサーバーからクライアントにプッシュされます。(典型的な RDBMS をはじめとする) サーバー・サイドのほとんどのデータ・ソースは非同期です。以前の Meteor では、非同期更新ストリームを生成するために、ポーリングして差分をとるアルゴリズムを使用していましたが、現在の Meteor リリースでは、以前より効率的なドライバーとして、MongoDB の操作ログを解析して可能な場合には (oplog tailing として知られる) ストリームを生成するドライバーを備えています。近い将来、Meteor は RethinkDB の変更フィードなどの、ネイティブ・リアルタイム・データベースからの非同期フィードを統合するかもしれません。

この記事のサンプル・アプリケーションにひと通り取り組んだ今、Meteor はリアルタイム非同期ストリーミング更新 Web アプリケーションを対象として設計されていることは理解できるはずです。

一般に、このようなタイプのアプリケーションは、極めてインタラクティブなシングル・ページ UI で構成されます。ユーザーは通常、新しいページのロードを体験することはなく、ユーザーの操作 (またはデータの変更) に応じて、表示されているページの一部が瞬時に更新されます。ネットワークでのラウンドトリップによる遅延はほとんどないか、皆無です。シングル・ページ・インターフェースでは、ありとあらゆる方法でページを部分的に更新できるため、このインターフェースによってアプリケーションが制限されることはまったくありません。この設計は、ワード・プロセッサーやスプレッドシートなどのスタンドアロンのデスクトップ・アプリケーションを連想させます。

このようなタイプの Web アプリケーションは、クライアント・ブラウザー上で JavaScript アプリケーション・コードをロードするのが通常です。このコードが、ブラウザーの DOM の操作、CSS スタイル設定の変更、新規 HTML 要素/コード/スタイルの生成、そしてブラウザーが提供するその他の API の使用に動的に対処して、ユーザーとの対話を管理します。ユーザーとの対話は、一貫してクライアント・サイドのコードによって制御されるため、アプリケーションが最初にロードされる以外で、ネットワーク経由で追加の HTML やスタイルがロードされることはありません。このコードはまた、アプリケーションの機能を実装するために、クライアントとサーバーの間でのデータの受け渡しも行います。実際には、ブラウザーは JavaScript で作成されたリッチ・クライアント (ファット・クライアントとも呼ばれます) アプリケーションをロードして実行します。

サーバー・サイドでは、クライアントからのデータをセキュアに提供して同期化するエンドポイントがセットアップされます。レガシー・バックエンドでは、RPC、XML ベースの Web サービス、RESTful なサービス、またはその他の JSON スタイルの RPC 呼び出しを使用することができます。今どきのバックエンドであれば、多くの場合、データの効率的送受信、偶発的切断に対する回復力、現行の各種トランスポートのサポート、そしてトポロジーの拡張性を目的に設計された独自仕様のプロトコルによって、サーバーから非同期でデータをストリーミングします。


まとめ

Meteor に関するインタビュー

Meteor の共同創始者 Matt DeBergalis 氏への Sing Li によるインタビューで、Meteor プロジェクトの背景情報と製品の計画について詳しく学んでください。

Meteor チームは、シングル・ページの極めてインタラクティブなリアルタイムの Web アプリケーションを作成したいと思うすべての人に均等な機会を与えられるように取り組んでいます。ほとんどのユーザーは、昔ながらの一度に 1 つのページというスタイルよりも、このようなアプリケーションを選択します。Facebook の Instagram、Google Gmail、Microsoft Hotmail、Yahoo Mail をはじめ、主要な Web ベースのメール・サービスやオフィス・サービスの多くでは、このアプリケーション・アーキテクチャーを採用しています。大規模な技術会社や、十分な資金を持っている新興企業などで開発されたものを除き、シングル・ページのインタラクティブなリッチ・クライアント Web アプリケーションの例はそう多くはありません。それは、このような Web アプリケーションを構築するのは難しく、多大な作業とリソースが必要になるためです。Meteor の中核となる使命として表明されているのは、このクラスのアプリケーションを容易に構築できる基礎を提供することです。

Meteor が登場したことにより、今こそ、しまい込んでいて長い間忘れられていたアプリケーションのアイデアをひと通り再検討し、これらのアプリケーションを一般公開サービスに変換することが、人を引きつける企てとなるかどうかを調べる絶好のタイミングです。Web アプリケーションをすでに作成または保守しているとしたら、ますます増え続けるアプリケーション開発ツールの選択肢の中で、Meteor が最も有力なツールであることがわかるはずです。


ダウンロード

内容ファイル名サイズ
Sales Portal and Foto Share codewa-meteor-webapps.zip548KB

参考文献

学ぶために

  • Meteor: Meteor Webサイトを探索してください。
  • Meteor のドキュメント: Meteor の公式ドキュメントで、最新機能や更新を調べてください。「Quick start!」ガイドを参考にすれば、Meteor をすぐに立ち上げることができます。
  • Atmosphere リポジトリー: コミュニティーでコントリビュートされている、そのまま統合できる何千というパッケージを調べてください。これらのパッケージは、Meteor アプリケーションに追加することができます。
  • 「Deploy meteor apps on Bluemix」: Meteor アプリケーションを Bluemix にデプロイするのは簡単です。この短いスクリーンキャストの指示に従ってください。
  • MongoDB: MongoDB NoSQL データベースは JSON スタイルの文書を格納します。このデータベースの簡潔なクエリー構文は、クライアント・サイドとサーバー・サイドの Meteor アプリケーション・コードの両方で広範に使用されます。
  • jQuery: さまざまな jQuery バージョンに用意されている多数のプラグインのリストをはじめ、jQuery フレームワークに関するあらゆる情報を調べてください。

製品や技術を入手するために

  • Meteor: Meteor は GitHub からダウンロードして入手することができます。

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Web development, Open source
ArticleID=936620
ArticleTitle=Meteor を使用したインスタント Web アプリケーション
publish-date=08062015