テンプレート API

<template name="foo"> ... <template> のように宣言されたテンプレートは Template.foo 関数のように参照することができます。この関数が呼び出された際には HTML の文字列を返却します。

同じテンプレートが複数回ページにて出現します。そしてそれらの出現はテンプレートインスタンスと呼ばれます。テンプレートインスタンスには「作成中」、「ドキュメント組み込み済」そしてその後「ドキュメント離脱」「消滅」といったライフサイクルがあります。いつテンプレートインスタンスが削除されたのか、あるいは置き換えられたのか、そして後始末が必要なのかといった状態の判断を Meteor は開発者にかわり管理します。データをテンプレートインスタンスに関連付けることができ、ドキュメントに組み込まれた場合はDOMノードを参照することができます。

さらに Meteor は周りのHTMLが新しいDOMノードで再描画された場合でも、テンプレートインスタンスとその状態を維持します。テンプレートの呼び出し方が同じであっても、Meteor はインスタンスのノードが作成されたか消滅したかを考慮しません。preserve か定数領域を使うことで同じDOMノードを維持することを要求することができます。

名前が指定されたテンプレートに設定できる数々のコールバックと命令があり、それらはすべてのテンプレートのインスタンスに適用されます。下記にその詳細を記します。

原文: http://docs.meteor.com/#templates_api
  • [訳文の最終確認 2013/12/23 (JST) - 最新バージョンが0.7.0.1 の時点での内容]
  • [訳文の最終更新 2013/07/01 (JST) - 最新バージョンが0.6.4 の時点での内容]

Template.myTemplate([data])

クライアントサイド

HTMLを生成するにあたり、テンプレートを指定して実行します。

引数

  • data オブジェクト

    省略可能。テンプレートを呼び出す際にデータを指定します。

テンプレートヘルパの中で呼び出された場合の Meteor.render の出力、あるいは反応可能なHTMLが存在する他の設定により呼びだされた場合、結果として出力されるHTML には反応可能なDOM要素として描画されるよう注釈がつきます。他の場合についてはHTMLに注釈はつかず静的となります。


Template.myTemplate.rendered = function () { ... }

クライアントサイド

テンプレートのインスタンスが描画された時のコールバックを指定します。

このコールバックは Template.myTemplate がDOMノードに描画され、ドキュメントに組み込まれた際に一度呼ばれ、テンプレートのいずれかの部分が再描画された場合に再度呼び出されます。

コールバック関数の中身においては、this はテンプレートの出現に対し一意となるテンプレートのインスタンスで、再描画に渡り永続します。インスタンスオブジェクトの初期化と後始末については crteated と destroyed コールバックを使用してください。


Template.myTemplate.created = function () { ... }

クライアントサイド

テンプレートのインスタンスが生成された時のコールバックを指定します。

このコールバックは myTemplate の実行が新しいテンプレートの出現を示し、既に存在するテンプレートインスタンスの再描画ではない場合に呼び出されます。コールバック関数の中身においては、this は新たなテンプレートインスタンスオブジェクトです。このオブジェクトに設定したプロパティは rendered と destroyed コールバックとイベントハンドラより参照可能です。

このコールバックは一度呼ばれ、また一番最初に呼ばれるコールバックです。すべての created は対応する destroyed を持ちます。これはつまり、あるテンプレートインスタンスオブジェクトのインスタンスを created にて this より獲得したのならば、最終的に destroyed で同じオブジェクトを獲得することを意味します。


Template.myTemplate.destroyed = function () { ... }

クライアントサイド

テンプレートのインスタンスが消去される時のコールバックを指定します。

このコールバックはどんな理由であれ、出現したテンプレートがページより消滅し、再描画によって書き換えられなかった場合に呼び出されます。コールバックの中身においては、this は消去されつつあるテンプレートインスタンスとなります。

このコールバックは後始末、あるいは create でほどこした外部的な効果の差し戻しにとても便利です。一度だけ呼び出され、呼び出すことができる最後のコールバックです。


Template.myTemplate.events(evetMap)

クライアントサイド

このテンプレートへのイベントハンドラを指定します。

引数

このテンプレートのインスタンス群のイベントハンドラを宣言します。複数回呼び出した場合は既存のものに加える形で新しいイベントハンドラを追加します。

イベントマップの詳細と、イベントマップが Meteor においてどの様に動くかについては イベントマップ をご参照下さい。


Template.myTemplate.helpers(helpers)

クライアントサイド

このテンプレートで利用可能なテンプレートヘルパを設定します。

引数

  • helpers オブジェクト型

    名前によるヘルパ関数の辞書。

それぞれのテンプレートは専用に作成されたヘルパ群のローカルの辞書を持ち、この関数を呼ぶとテンプレートの辞書にヘルパが追加されます。

例:

Template.myTemplate.helpers({
  foo: function () {
    return Session.get("foo");
  }
});

Handlebars で、このヘルパーは {{foo}} として実行されます。

次の文法は同等ですが、予約語を使ったプロパティ名に対しては無効です。

Template.myTemplate.foo = function () {
  return Session.get("foo");
};

Template.myTemplate.preserve(selectors)

クライアントサイド

再描画の際に個々のDOM要素が保持されるルールを設定します。

引数

  • selectors 配列あるいはオブジェクト

    配列の要素各々にて、多くとも1つの要素にマッチするCSSセレクタからなる ['.thing1', '.thing2'] の様な配列。あるいはセレクタの辞書とノードの名前付けを行う関数 (下記をご確認ください)。

再描画の際にDOM要素を、既にドキュメントに組み込まれた要素を周りのHTMLが置換される時に残存させる形で保持することができます。テンプレートの再描画がテンプレートに含まれるテキストフィールド、iframe、そして他の神経質な要素に介入する必要がないと示すことができます。保持される要素は必ず古いDOMの中のノード、そして新しいHTMLの中のタグとして表現される必要があります。Meteor は保持された要素の周りのDOMを修正します。

  • デフォルト設定では、新しく生成された Meteor アプリケーションは preserve-input パッケージが含まれています。このパッケージは一意の id 属性を持つか 囲んでいるidを持つ要素の中で一意となる name 属性を持つ input、textarea、button、select、そして option 要素をすべて保持します。デフォルト設定は preserve-inputs パッケージを取り除くことで簡単に無効にできます。

DOM要素を元々と変わらないあるいは編集された要素に差し替えることで、現在の要素と異なる結果となる様々な場面にて保持機能は有効にはたらきます。これには下記のケースが含まれます。

  • テキスト入力フィールドと他のフォーム要素
  • CSSアニメーションが設定された要素
  • iframe
  • JavaScript のコードから参照されているノード

DOM全体、1つの要素とその子要素、Meteor によって描画されていないノード群を保持したい場合、かわりに 定数領域 を使ってください。

ノードを保持するには、それぞれのセレクタがそのテンプレートの中の多くとも1つの要素にマッチするセレクタのリストを渡して下さい。テンプレートが再描画された際、セレクタは古いDOMと新しいDOMに対し評価が行われ、Meteor は周囲のHTMLを修正する際に古い要素を再利用します。

preserve の他の使い方は、引数にそれぞれのセレクタに対する名前付けの関数をとり、複数のノードに合致するセレクタを許可します。ノードの名前付け関数にはノードが渡されます。関数はそれぞれの要素に対し一意となる名前を表す文字列を返すか、保持対象から除外するのであれば false を返して下さい。

たとえば、テンプレートの中のid を持つすべての <input> 要素を保持するには下記のコードを使用してください。

Template.foo.preserve({
  'input[id]': function (node) { return node.id; }
});

セレクタはテンプレートのトップレベルをルートとして解釈されます。テンプレートの出現はそれぞれ独立して処理されるため、セレクタはページ全体を考慮する必要はなく、テンプレート一つの出現に対して一意としてください。セレクタはサブテンプレートの中のノードであってもマッチします。

ノードの保持機能を使っても、属性とコンテンツは保存され 新しいHTMLへと更新されます。テキストフィールドの文字はカーソラと選択範囲が触れられていない場合、テキストフィールドにフォーカスが当たっていなければ保持されません。iframe は遷移状態を保持し、アニメーションはパラメータが変更されない限り引き続き実行されます。

DOM API にそなわる制約によりノードが保存できないいくつかのケースがあります。たとえば、要素のタグ名を変更することはできません、そして親要素に対して相対となるようにや、他の保持されたノードになるような移動はできません。この様な理由から更新によって順序が変更されたり、親要素が変更されたノードは保持されません。


テンプレートインスタンス

テンプレートインスタンスオブジェクトはドキュメントにおけるテンプレートの出現に相当します。DOMの参照に利用することができ、ページの再描画を通して維持される割り当てられたプロパティになることができます。

テンプレートインスタンスオブジェクトは、created、rendered そしてdestroyed テンプレートのコールバックの this の値として、そしてイベントハンドラの引数として参照することができます。

解説するプロパティと関数に加え、'_' で名前が始まるプロパティについては開発者にて使用できることが保証されています。オブジェクトの初期化あるいは後始末を行うには created あるいは destroyed コールバック関数を使用してください。

findAll、find、firstNode と lastNode へは rendered のコールバックとイベントハンドラからのみ参照することができます。テンプレートインスタンスがDOMの中に存在していることが前提のため、 created と destroyed から参照することはできません。


this.findAll(selector)

クライアントサイド

テンプレートインスタンスの中で selector に合致するすべての要素を探します。

引数

  • selector 文字列型

    テンプレートのコンテンツを対象とした、合致させるべき CSS セレクタ

selector に合致するDOM要素の配列を返却します。

テンプレートのインスタンスはこのセレクタのルート要素として振舞い、テンプレートとサブテンプレートの中の要素のみ、このセレクタの対象として合致します。


this.find(selector)

クライアントサイド

テンプレートインスタンスの中で selector に合致する1つの要素を探します。

引数

  • selector 文字列型

    テンプレートのコンテンツを対象とした、合致させるべき CSS セレクタ

selector に合致するDOM要素を返却します。もし指定したセレクタに合致したコンテンツが無ければ null を返します。

テンプレートのインスタンスはこのセレクタのルート要素として振舞い、テンプレートとサブテンプレートの中の要素のみ、このセレクタの対象として合致します。


this.firstNode

クライアントサイド

テンプレートインスタンスの中のトップレベルの最初のDOMノードです。

selector に合致するDOM要素を返却します。もし指定したセレクタに合致したコンテンツが無ければ null を返します。

テンプレートのインスタンスはこのセレクタのルート要素として振舞い、テンプレートとサブテンプレートの中の要素のみ、このセレクタの対象として合致します。


this.lastNode

クライアントサイド

テンプレートインスタンスの中のトップレベルの最後のDOMノードです。


this.data

クライアントサイド

このインスタンスが最後に実行された際のデータを指します。

このプロパティはテンプレートのトップレベルにあてられたデータへの参照を提供します。テンプレートが更新されるたびに更新されます。参照はリードオンリで反応可能ではありません。


Meteor.render(htmlFunc)

クライアントサイド

データの変化に応じて自動的に更新するDOMノードを作成します。

引数

  • htmlFunc 関数

    HTMLの文字列を返す関数

描画されるHTMLを生成する関数。実行した直後に1度呼び出され、その後データが変更されると毎回再実行されます。関数のかわりにHTMLの文字列を指定することもできます。

Meteor.render はリアルタイムで自動的に更新される DocumentFragment (DOMノードの連続) を作成します。ほとんどの Meteor アプリケーションは直接呼び出す必要はなく、テンプレートを使用し、Meteor がレンダリングを処理を担当します。

引数にはHTML文字列を返す htmlFunc を指定して下さい。Meteor.render は引数に指定された関数を呼び出し、出力をDOMノードへ流し込みます。同時に、htmlFunc の引数として指定されたデータを追跡し、コールバックのつなぎ込みを自動的に行います。その結果、データの更新があった場合は毎回 htmlFunc の再実行と、その場でのDOMノードの更新がおこなわれるようになります。

返却された DocumentFragment はDOMのお好みの位置に直接挿入することができます。挿入されたノードは、画面から消えるまで更新されつづけます。その後は自動的に後始末が行われます。後始末の詳細については、Deps.flush を参照してください。

Meteor.render は反応可能な算出の中で htmlFunc を実行することにより、htmlFuncのデータ依存関係を追跡します。その結果として、利用されている任意の反応可能なデータソースの変更に対応することができます。詳細については、または反応可能なデータソースを自作する方法を学ぶにあたっては、反応可能性 (Reactivity) を参照してください。

例:

// クライアントサイド: オンラインのプレーヤ人数を表示します。
var frag = Meteor.render(function () {
  return "<p>" + Players.find({online: true}).count() +
    " 人のプレーヤがオンラインです。</p>";
});
document.body.appendChild(frag);

// サーバサイド: しばらく待機 (idle) 状態が続いているプレーヤを探し出し、
// それらのプレーヤをオフライン状態として登録します。
// クライアントの画面上に表示される人数は自動的に更新されます。
Players.update({idleTime: {$gt: 30}}, {$set: {online: false}});

イベントマップ

いくつかの関数はイベントマップを保有します。イベントマップは、プロパティが扱うイベント群を指定し、値がそれらのイベントを扱うハンドラ群となったオブジェクトです。プロパティは次のいくつかの形式の中から1つを選ぶことができます。

  • eventtype

    'click' の様にイベントの種類でマッチします。

  • eventtype selector

    イベントの種類でマッチしますが、CSSセレクタにマッチする要素で発生した時のみです。

  • event1, event2

    同じハンドラ関数に1種類以上のイベントを指定します。カンマ区切りのリストを使用して下さい。

ハンドラ関数には次の2つの引数が渡されます。イベントに関する情報を保持する event、そしてハンドラが定義されたテンプレートのテンプレートインスタンスです。ハンドラ関数は現在イベントを扱っている要素のコンテキスト次第では、コンテキストに関する情報を this を使い参照することもできます。Handlebars のテンプレートでは、要素のコンテキストは #with や #each の様なブロックヘルパで指定された要素の Handlebar のデータコンテキストとなります。

例:

{
  // 要素をとわず、クリックされた時にハンドラ関数が呼び出されます
  'click': function (event) { ... },

  // 'accept' クラスの要素がクリックされた際にハンドラ関数が呼び出されます
  'click .accept': function (event) { ... },

  // 'accept' がクリックされるか、キーが押された時にハンドラ関数が呼び出されます
  'keydown, click .accept': function (event) { ... }
}

大抵のイベントは発生元の要素から、DOMツリーをつたい他の要素に伝達 (bubble up) されます。たとえば、'click p' はクリックがパラグラフ (訳注:<p>タグを指すものと考えられます) の中のリンク、span、あるいは他の要素で発生した場合であっても、パラグラフの中の要素で発生した click すべてを受け取ります。イベントの発生元となる要素は target プロパティを通して参照が可能です。一方で、セレクタにマッチし、それを現在処理しているハンドラの要素は currentTarget となります。

{
  'click p': function (event) {
    var paragraph = event.currentTarget; // いつでもp要素を指します
    var clickedElement = event.target; // p要素あるいは子要素の可能性があります
  }
}

セレクタがイベントが伝達している複数の要素にマッチする場合、複数回呼び出されます。例を挙げるならば 'click div' と 'click *' の場合などです。もしセレクタが指定されていない場合、ハンドラはイベント発生元に対して1回のみ呼び出されます。

ハンドラ関数に渡されるイベントオブジェクトにおいては、次のプロパティとメソッドが利用可能です。

  • type 文字列型

    "click", "blur" や "keypress" の様なイベントの種類

  • target DOM要素

    イベントの発生元の要素

  • currentTarget DOM要素

    イベントを現在処理している要素。イベントマップの中のセレクタにマッチした要素です。イベントの伝達を考慮した場合、target と同等かあるいは target の親世代となるでしょう。イベントの伝達とともに値は変化します。

  • which 数値

    マウスイベントの場合、マウスボタンの番号 (1=左、2=中、3=右) です。キーイベントの場合、文字あるいはキーコードです。

  • stopPropagation()

    イベントの親の他の要素への伝達を停止します。同じ要素に合致するセレクタを持つイベントマップがあれば、そのハンドラまでは呼び出しが行われます。

  • stopImmediatePropagation()

    このイベントマップの中の他のハンドラ、伝達により到達するハンドラ、他のイベントマップのハンドラを含めたイベントハンドラがこのイベントで実行されることを防ぎます。

  • preventDefault()

    リンクから遷移が発生したり、フォームを送信したりするなど、ブラウザが通常このイベントに対してとり行うアクションを停止します。他のハンドラはこの場合でも実行されますが、この処理を覆すことはできません。

  • isPropagationStopped()

    このイベントに対して stopPropagation() が実行されているかどうかを返却します。

  • isImmediatePropagationStopped()

    このイベントに対して stopImmediatePropagation() が実行されているかどうかを返却します。

  • isDefaultPrevented()

    このイベントに対して preventDefault() が実行されているかどうかを返却します。

ハンドラ関数から false を返却すると stopImmediatePropagation と preventDefault の両方をイベントに対して実行した事と同じ効果が得られます。

イベントの種類と利用方法は下記が含まれます。

  • click

    リンク、button、フォーム要素、div を含むすべての要素の上で発生したマウスクリックです。リンクのクリックから発生する遷移を防ぐ場合 preventDefault() を使ってください。いくつかのキーボードより要素をアクティブ化する方法からも click イベントが発生します。

  • dbclick

    ダブルクリック。

  • focus, blur

    テキスト入力欄あるいは他のフォーム要素がフォーカスを獲得あるいは喪失しました。tabindex プロパティを指定した要素であればフォーカスの移動が期待できます。リンク、チェックボックス、ラジオボタンが何もしない状態でフォーカス可能かはブラウザによって異なります。これらのイベントは伝達はおこなわれません。

  • change

    チェックボックスあるいはラジオボタンの状態が変化しました。テキストフィールドの場合 blur かキーイベントを使い変化に対応してください。

  • mouseenter, mouseleave

    ポインタが要素の領域に侵入した、あるいは離脱しました。これらのイベントは伝達はおこなわれません。

  • mousedown, mouseup

    マウスのボタンが新たに押下あるいは解放されました。

  • keydown, keypress, keyup

    ユーザがキーボードのキーを押しました。keypress はテキストフィールドの入力を捉える際に便利です。keydown と keyup は矢印キーかメタキーに利用することができます。

  • tap

    要素の上でのタップ。タッチ可能なデバイスでは click のかわりにすぐに実行されます。これらのイベントは touchmove と touchend を合成しています。

他のDOMイベントも同様に利用可能ですが、上記のイベントはすべてのブラウザで同じように動くよう、Meteor がいくらかの考慮をおこなってます。


定数領域

{{#constant}} ... {{/constant}} ブロックヘルパを使い、定数として作成されたテンプレートの領域は再描画が行われません。#constant ブロックヘルパのコンテンツは、それを含むテンプレートが再描画された場合でもそのままの状態で保存されます。テンプレートの他の部分の変更は preserve と同じ形で周囲の更新が行われます。個々のノードの保存とは異なり、定数領域はノードの同一性だけではなく、属性とコンテンツも保持されます。このブロックのコンテンツは周囲のテンプレートが表示された場合に一度評価が行われます。

定数領域を使うことで Meteor のテンプレートに Meteor に属さないコンテンツを埋め込むことができます。多くのサードパーティ製のウィジェットは独自のコードでDOMのノードの作成と管理を行います。ウィジェットあるいはライブラリが子要素を作成する空のエレメントをテンプレートの中に設置するのが典型的な形です。通常、Meteor が周囲のテンプレートを再描画する場合はテンプレートにおいて要素が空であったことを理由に、新たに生成された子要素は削除されます。一方コンテナが #constant ブロックに含まれていた場合、そのDOMの中のコンテンツに何が残されていたとしても立ち残されます。

  • 定数領域は Meteor に属さないコンテンツを埋め込むために設計されています。定数領域の中ではイベントハンドラと反応に必要な依存性は現在の所きちんと動きません。

反応の隔離

それぞれのテンプレートはテンプレートが保有する反応可能な算出にしたがい更新されます。テンプレートが Session.get やデータベースクエリの作成など、反応可能なデータソースにアクセスした際は、データの更新時にテンプレート全体の再描画が発生するデータの依存関係を生成します。これは一定の変更に対する再描画の回数が、HTML がテンプレートにどの様に分割されて格納されているかに左右されることを意味します。

基本的には、再描画の回数はそれほど重要ではありませんが、パフォーマンスの観点より、より細かい制御を行いたい場合、{{#isolate}} ... {{/isolate}} ヘルパを使用することができます。#isolate ブロック内に生成されたデータの依存関係はそのブロック内に限定され、その依存によって親のテンプレートが再描画されることはありません。ブロックヘルパを使うことで、新しいサブテンプレートにコンテンツを引き出すことによって得られる利益が実質的にもたらされます。

Meteor Kaiso は JavaScript を使ったフルスタックフレームワークである Meteor のドキュメントの日本語訳と、Meteor を使った開発の際に役立つナレッジを紹介します。Meteor については「Meteorとは」をご参照ください。

サンプルコードから学ぶ Meteor アプリ入門

サンプル1 - 順位表

サンプル2 - イベント告知

Meteor アプリ開発ガイド(独自コンテンツ)

Meteor アプリでの CRUD 基本操作 - チャットアプリを例として

insecure パッケージと autopublish パッケージ - チャットアプリ その2

さらに Meteor アプリケーション作成の際に必要な心得をマスターするのであれば公式ドキュメント Concept の日本語訳、設計概念に進みましょう。

白熱のページ

An Introduction to Meteor
Meteor の導入, プラクティスを詳しく解説。スクリーンショット付きで Windows 環境でのケースが紹介されているので参考になる部分が多いかと思われます。公開環境にデプロイする際の心がけについても解説
Meteor on Windows!
非公式な Meteor の Windows 向けビルドとそのインストーラが公開されています。
Meteor を使用したインスタント Web アプリケーション
IBM developerWorks による Meteor でセールスリポートを可視化するアプリケーションと、写真をシェアするアプリケーションを作ってみようという記事。画像の扱いについてコンセプトモデルという註もあるものの、参考になる点が多いかと思います。末尾には Meteor プロジェクトのメンバーとのインタビューが含まれており、チームの現在のウェブ開発を取り巻く状況の認識と Meteor の役割が語られています。
Best Learning Resources for Meteor.js
Meteor アプリケーション開発の入門に役立つページへのリンク集。必要となる JavaScript の言語仕様を解説するページや MongoDB に関するトピックス、Meteor アプリケーションのコード例を紹介したページ等へのリンクが紹介されています。
Discover Meteor - Learn how to build real-time JavaScript web apps
実際の Meteor 利用シーンを想定した複数のサンプルから構成される Meteor のチュートリアル (一部を除き有償, 複数プランあり)
Meteor meets Mallory
Meteor アプリケーション作成の際にセキュリティの面から留意すべきことを解説。XSS 対策や Mongo に対するインジェクション防止。
The Meteor Blog
Meteor のオフィシャルブログ。Meteor の開発に役立つ情報が掲載されることがあります。最新のリリース情報を確認することもできます。
Crater.io: Meteor Links & Discussion
Meteor に関する最新情報が寄せられたソーシャルニュースサイト
Atmosphere
有志によって作成された Meteor のスマートパッケージが集約されたサイト。Perl でいう CPAN、PHP でいう pear、Ruby でいう gem、node でいう npm にあたるライブラリ。
Building Rabbit in Meteor | Nettuts +
Meteor を使い twitter クローンを作成する記事
Meteorpedia
Meteor 公式ドキュメントの補遺やチュートリアルの提供を目指して運営されている Wiki 。現在の時点でもデザインパターンや Nodojitsu をはじめとする各種 PaaS へのデプロイ方法が充実しています。
Building large, modular apps in Meteor | Exponential.io
大規模アプリケーションを作る際に必要なモジュール化とそのディレクトリ構造について解説された記事。
Improving the Performance of your Meteor JS projects
Meteor アプリケーション開発に役立つ Tips の紹介。Session の使い方や効率のよいクエリの発行の仕方、ビュー開発のコツ等。
stevemanuel / meteor-GAevents
Meteor アプリケーション上でのイベントを Google Analytics で簡単に追跡できる形にした Meteorite パッケージ。

より核心へ

Evented Mind - A place to love learning technology
Meteor のアーキテクチャを詳しく紹介する記事が充実しています。URLに合わせページの分割を行う機能を提供するIronRouterの解説や Meteor アプリケーションにてクライアント・サーバの結合がどの様に行われるかなどが手順を追って解説されています。
MeteorHacks
Meteor アプリのスケーリングやロードバランシングを行う際の Tips をはじめとし、Meteor の内部実装に関わる様々な試みを紹介しています。
Essential Meteor Performance Tips | Nettuts+
Smart Collections をはじめとして、 MeteorHacks (上掲サイト) にて紹介された Tips を使い Meteor のパフォーマンスを向上させる方法
Unofficial Meteor FAQ
Meteor のカスタマイズ方法など、公式サイトでは紹介されていないディープな情報。Meteor のブラウザサポート状況についても軽く触れられています。
Scaling Meteor with Amazon EC2 and Elastic Load Balancer — Skimbox
スティッキーセッションを利用し、 AWS Elastic Load Balancer 配下にて Meteor アプリケーションを利用する方法。
Meteor Web Apps on Mobile
たとえば、モバイルの Safari や Chrome で長時間アクセスされずバックグラウンドなタブに回された場合、Meteor アプリケーションの subscription はどうなるの?等の考察。
Why Is My Meteor App Not Updating Reactively?
Meteor の特にクライアントサイド根幹を担う反応可能な算術、 Deps の使い方。効率的なデバッグ方法
Benjamin Harris : Showing "loading" in Meteor
画面遷移時に遅いと感じたら。読込中を表示する方法について解説されています。
onmodulus/demeteorizer
Meteor プロジェクトを node.js が動く環境であればどこでも動く形のプロジェクトへ変換する demeteorizer プロジェクト
How to Build Your First Meteor App and Discover Your Inner Artist — Riparian Data
Boston Meteor Meetup group にてデモに使用された Meteor と Canvas (と d3js) を使ったマルチプレーヤで同時に絵を描くアプリケーションの解説

Meteor アプリのテスト方法

Test Driven Development with Meteor - SitePoint
Meteor向けに mocha を使い作られたテストフレームワーク laika の利用方法
alanning/meteor-load-test
Meteor アプリに対し負荷 (ロード) テストを行うツール。注意: *.meteor,com にデプロイしたアプリに対して負荷テストは行わないでください。ご自分のサーバを使いお試しください。
Testing With Meteor, CoffeeScript and Mocha
Mocha, CoffeeScript を使ったMeteorのテスト方法

お上を説得する資料

Why Meteor will kill Ruby on Rails
Rails と比較した場合学習コストに優れるという側面の紹介
Why the future is NOT RESTful
Webの進化に伴いRESTは廃れるという予想
Isomorphic Javascript
どこでも動く JavaScript 。もうSQLもサーバサイドアプリケーション用の言語も学ばず JavaScript でどこでもいける。
Things they don’t tell you about MongoDB
楽観論だけでは受け付けないプロフェッショナル。Meteor 内部にて使用されている MongoDB の考慮すべき制約について。

Meteor の DB に RDB を使う方法

How To Use MySQL With Meteor
MySQL を Meteor のバックグラウンドとして利用する方法
Live updates to Meteor from Postgres
Postgre SQL を Meteor で利用する方法 (MongoDB経由)

その他のトピック

Telescope
Meteor で作られたソーシャルニュースサイト
Made with Meteor!
Meteor を使って作成されたアプリケーションの実例集
Build Meteor apps in the browser with Action.IO and MongoLab
WebIDE と MongoLab (Mongo DBのデータベースを提供する PaaS環境) を使ったクラウドのみで開発からデプロイまでを完結させる手法の解説
NoBackend: Front-End First Web Development
もう一つのサーバサイド抽象化の流れ
The Backend as a Service Ecosystem Map Update & New Trends: Migration Toward the Middle
Kinvey による Baas (Backend as a Service) Map。Meteor は Parse (2013年4月に Facebook により買収) の直下に描かれています

設計概念

原文: http://docs.meteor.com/#concepts
  • [訳文の最終更新 2013/12/23 (JST) - 最新バージョンが0.7.0.1 の時点での内容]

Meteor 開発チームはこれまで貢献可能な形でそれぞれ Single-page JavaScript Applications* を手書きで書いてきました。 アプリケーション全体を1つのデータフォーマット、JSONと1つの言語、JavaScript で書くことはとても楽しいことです。 Meteor はそういったアプリケーションを書く際に必要となる全てを提供します。

(訳注) * Single Page Application、通称 SPA。ユーザがブラウザ内でコンテンツ間を遷移する時にブラウザにヘッダからフッタまで、 全てのHTMLをブラウザに再度読み込ませるのではなく、 Ajax を用い動的にコンテンツデータのみを切り替え、データ通信量、 描画時のクライアント負荷を最小限に抑えた形の Web アプリケーションを指します。

Meteor とは

Meteor とは2つのものを指します。

パッケージライブラリ: アプリケーションに必要となるだろう事前に書かれた、独立したモジュール。
大抵のアプリケーションが使うであろう沢山のコア Meteor パッケージがあります (たとえば、寄せられるHTTP接続を操作する webapp、そしてデータが変更された時にその場で更新されるHTMLテンプレートを作成する場合に使う templating) 。くわえてメール送信機能を提供する email のような、あるいはアプリケーションにそのまま利用できるすべての機能を備えた一連の Meteor Accounts (account-password, accounts-facebook, accounts-ui など) のような選択可能なパッケージがあります。そしてそれらの「公式な」パッケージ以上に、数千ものコミュニティーによって書かれたパッケージが Atmosphere に存在し、それらの一部はまさに望んでいた機能を提供してくれるかもしれません。
meteor と呼ばれるコマンドラインツール
meteor は make、rake、あるいは Visual Studio の見えない部分に当たるビルドツールです。アプリケーション内のすべてのソースファイルと素材を寄せ集め、それらを必要なビルドステップへと持ち込み (CoffeeScript のコンパイル、CSSの最適化、npm モジュールのビルドあるいはソースマップの作成など) 、アプリケーションが使用するパッケージを取得し、そして実行可能な独立したアプリケーションバンドルを出力します。開発モードではファイルを変更した場合はいつでもすぐに変更がブラウザで確認できるよう、それらすべては相互作用的に行われます。環境に依存せず利用するのにとても簡単で、かつ拡張性のある方法です。たとえばビルドプラグインパッケージをアプリケーションに追加すると、新しい言語とコンパイラへのサポートを追加することができます。
Meteor パッケージシステムの要となる思想は「すべてはブラウザであろうとサーバであろうと同じように動く(もちろん、成立可能な範囲でどこでも-ブラウザがメールを送信できませんし、サーバでマウスイベントを拾うことはできません)」ということです。Meteor のすべてのエコシステムはこれをサポートするために生まれました。
meteor はまだ Atmosphere からパッケージを取得することができません。もし Atmosphere を使おうとしているのなら、Atmosphere パッケージのダウンロードと管理を行うツール Meteorite をご確認ください。
Meteor 1.0 においては、ビルドツール meteor は Atmosphere の完全なサポートを行う予定です。

アプリケーションの組み立て

Meteor アプリケーションはウェブブラウザ (クライアント) で実行される JavaScript と、 Node.js コンテナの中で動く Meteor サーバで実行される JavaScript、そしてそれを支える HTML フラグメント、CSS 定義、静的データより構成されます。Meteor はそれらの異なるコンポーネントのパッケージ化と配信を自動化します。それだけてなく、ディレクトリ構造のなかでそれらの構造をどう構成するかについて、きわめて柔軟に対応します。

サーバ側の唯一のデータは JavaScript です。Meteor は (client/ ディレクトリと public/ ディレクトリ配下のファイルを除き) 全ての JavaScript ファイルをかき集め Fiber* の中の Node.js サーバインスタンスにてそれらを読み込みます。Meteor では、サーバ側のコードは1つのリクエストに対し1つのスレッドの中で実行されます (Node の典型的な非同期コールバックのスタイルとは異なります)。Meteor 開発チームはこの同期実行モデルが典型的な Meteor アプリケーションに、より合致していると考えます。

(訳注) * Fiber: Node.js アプリケーションを同期的なプログラミングスタイルで記述することができる Node.js のサードパーティによる拡張機能。

クライアントサイドではより多くの形のファイルが存在します。Meteor は (server/ ディレクトリと public/ ディレクトリ配下を除き) 全ての JavaScript ファイルをかき集め、軽量化を行いそれぞれのクライアントに配信します。アプリケーション向けに、1つの JavaScript ファイルを使うか、ディレクトリ別に階層化するか、それらの中間を採用するかは自由です。

いくつかの JavaScript ライブラリは client/compatibility/ ディレクトリに配置した時にだけ有効となります。このディレクトリの中のファイルは新しい変数スコープへとラップされることなく実行されます。これはそれぞれのファイル空間のグローバル変数として宣言された変数がグローバル変数となることを意味します。くわえて、これらのファイルは他のクライアントサイド JavaScript が実行される前に実行されます。

client/, server/, tests/のいずれかのディレクトリ以外に配置されたファイルはクライアントサイドでも、サーバサイドでも読み込まれます! モデルの定義そしてその他の機能のために利用して下さい。Meteor はコードが実行されているのがクライアントサイドか、サーバサイドかによって挙動を変更するための isClient そして isServer という変数を提供しています。(test/ と名付けられたディレクトリに配置されたファイルはいかなる場所においても読み込まれません)。

パスワードや認証の手順が含まれるような機密性の高いコードは server/ ディレクトリに配置して下さい。

CSSファイルも同様にかき集められ、クライアントではserver/とpublic/配下に配置されたファイルを除き、1つのファイルとして受信されます。

デバッグの際には開発者モードを使うことでJavaScript と CSS ファイルが結合されずに送信することができます。

Meteor アプリケーションの HTML ファイルはサーバサイドフレームワークとはかなり異なる扱われ方をされます。Meteor は全てのディレクトリの HTML ファイルの<head>タグ、<body>タグそして<template>タグのスキャンを行います。<head>部と<body>部は別々に1つの<head>部と<body>部に結合され、クライアントサイドによる初回読み込み時に送信されます。

一方 Template 部は JavaScript 関数に変換され、Template オブジェクトより参照可能です。これは HTML テンプレートをクライアントに送信する本当に便利な手法です。更に詳しいことは コンセプト:テンプレート をご確認下さい。

最後に、Meteor サーバは public/ディレクトリ配下の全てのファイルを Rails や Django プロジェクトの様に配信します。これは画像や favicon.ico, robots.txt 等を配置する場所です。

たとえば Meteor.startup API を利用したり、読み込みの順番に神経質となる必要があるコードを、他のパッケージとの兼ね合いを含めて明示的に制御することができるスマートパッケージに移行したりすることは、読み込みの順番に神経質なコードを書く際にベストな方法です。しかしながら、時によってはアプリケーションの読み込み順序への依存は避けられないこともあります。アプリケーションの中の JavaScript ファイルと CSS ファイルは次のルールによって読み込まれます。

  • アプリケーションルートの lib/ ディレクトリにあるファイルが最初に読み込まれます。
  • main.* に合致するファイルが他より先に読み込まれます。
  • サブディレクトリに配置されたファイルが親ディレクトリよりも先に読み込まれます。つまり一番深い改装にあるファイルが最初(lib/配下の次)に読み込まれます。ルートディレクトリに配置されたファイルは (main.*に合致しないのであれば) 後に読み込まれます。
  • ディレクトリ内ではファイル名のアルファベット順に読み込まれます。

上記のルールは掛け合わされ、その結果、例えばlib/ディレクトリの中でまたアルファベット順に読み込まれます。そして複数の main.js ファイルが (いくつかのディレクトリに) 存在すれば、サブディレクトリに配置されたものが先行して読み込まれます。

データとセキュリティ

Meteor はクライアントに配布されるコードをローカルのデータベースとやり合う様にシンプルにします。個別のRPCエンドポイント作成やサーバからの返却の遅延を防ぐため手動でクライアントにデータをキャッシュしたり、データが変更されるたびに更新のメッセージを各クライアントに向け調整して配信する等を必要としない簡潔、シンプル、そして安全なアプローチです。

Meteor では クライアントとサーバは同じデータベースAPIを提供します。バリデーション手続きや四則演算結果の値の算出の様なしばしばサーバサイド、クライアントサイドそれぞれで実行されるコードはまさに同一のコードです。しかしDBにアクセスするコードはサーバサイドで実行された場合、直接アクセスを行いますが、クライアントサイドで実行された場合には間接的なアクセスとなります。この区別は Meteor のデータセキュリティーモデルの基本となります。

デフォルト設定では、Meteor アプリケーションは autopublish 並びに insecure パッケージを含んでいます。これらのパッケージはクライアントサイドにがサーバが持つDBへのフルアクセスを提供します。便利なプロトタイピングツールですが、商用環境についてはそうではありません。準備が整い次第、これらのパッケージは取り除いて下さい。

全ての Meteor クライアントは in-memory のデータベースキャッシュを含んでいます。クライアントサイドのキャッシュを管理するため、サーバは一連の JSON ドキュメント (≒DBに保存されたレコード) を publish し、クライアントはそれらを subscribe します。

現存する多くの Meteor アプリは、他のデータベースへのサポートも準備中ではありますが、その絶妙の相性より MongoDB をデータベースとして利用しています。 Meteor.Collection クラスは Mongo の collection の宣言とその操作のため利用され、Meteor の Mongo クライアントエミュレータである Meteor.Collection はクライアントサイド、サーバサイド双方のコードから利用することができます。

// collection を宣言します
// このコードはクライアントとサーバサイドに記述して下さい
Rooms = new Meteor.Collection("rooms");
Messages = new Meteor.Collection("messages");
Parties = new Meteor.Collection("parties");

// サーバサイド: 初回ドキュメントを挿入します
Rooms.insert({name: "Conference Room A"});
var myRooms = Rooms.find({}).fetch();
Messages.insert({text: "Hello world", room: myRooms[0]._id});
Parties.insert({name: "Super Bowl Party"});

それぞれのドキュメントセット (訳注≒テーブル内のレコード群) はサーバで publish 関数を使い宣言されます。この publish 関数はクライアントがドキュメントセットを subscribe するとき毎回実行されます。ドキュメントセットに含まれるデータは大抵の場合はデータベースクエリを publish するためのものです。

// サーバサイド: 全ての Room ドキュメントを publish します
Meteor.publish("all-rooms", function () {
  return Rooms.find(); // everything
});

// サーバサイド: 特定の Room に向けられた Message 全てを publish します
Meteor.publish("messages", function (roomId) {
  check(roomId, String);
  return Messages.find({room: roomId});
});

// サーバサイド: ログインユーザが閲覧可能な一連の Party を publish します
Meteor.publish("parties", function () {
  return Parties.find({$or: [{"public": true},
                             {invited: this.userId},
                             {owner: this.userId}]});
});

publish 関数はクライアントにより異なる結果を提供することができます。(上掲サンプルコード) 最後の例では、ログイン済みのユーザは公開、当該ユーザ保有あるいは招待 (invited) された Party ドキュメントのみを閲覧することをできます。

一度 subscribe すると、クライアントはそのキャッシュを高速なローカルデータベースとして利用します。クライアントサイドのコードは劇的にシンプルになります。読み込み時はサーバへのリクエスト・レスポンス待機はコストが高いため決して行いません。読み込みの対象はコンテンツのキャッシュのみに限定されます。クライアントサイドではコレクションの中の全てのドキュメントに対するクエリは、サーバがそのクライアントに向けて publish しているドキュメントを返却します。

// クライアントサイド: Party の subscription を開始します
Meteor.subscribe("parties");

// クライアントサイド: このクライアントに権限が与えられた Party 配列を返却します
return Parties.find().fetch(); // 同期処理!!

クライアントは知性的で、どの位のデータをキャッシュに保存するか、そしてネットワークトラフィックを制御するため subscribe 機能を有効化あるいは無効化することができます。subscribe 機能がが無効化された際には、そのドキュメントが他のアクティブな subscribe の対象になっていない限りそのドキュメントはキャッシュより削除されます。

クライアントサイドにて1つないしそれ以上のドキュメントが「変更」された場合、サーバに変更を要求するメッセージが送信されます。サーバサイドではクライアントから送信された「変更」が JavaScript の関数として書かれた許可/拒否のルールに反していないかチェックが行われます。サーバはすべてのルールをパスした「変更」のみ受け付けます。

// サーバサイド: クライアントに Party への追加を許可しません
Parties.allow({
  insert: function (userId, party) {
    return false;
  }
});

// クライアントサイド: 下記はうまくいきません
var party = { ... };
Parties.insert(party);

サーバが変更を許容したならば、その変更はデータベースへ適用されます。そして変更があったドキュメントを subscribe しているクライアントへと、自動的にその変更を伝搬します。もし拒否した場合、変更を失敗とし、サーバサイドのデータベースには変更を加えず、他のクライアントが変更を目にすることはありません。

とはいえ、 Meteor にはかわいらしい魔法があります。クライアントがサーバに書き込みリクエストを送信した直後には、サーバからのレスポンスを待たずしてローカルのキャッシュが更新されます。つまり画面はすぐに再描画されます。もしサーバが更新を許容した場合 (多くの場合クライアントサイドにて期待されるケースです) クライアントは1世代先の状態を手にしていたことになり、画面を更新するためにレスポンスを待つ必要もありません。もしサーバが変更を拒絶した場合、Meteor はサーバが返却した結果をもとにクライアントサイドのキャッシュを修正します。

上記すべてが集まって、遅延の埋め合わせを行います。クライアントには必要なデータのホヤホヤなコピーがあり、サーバのレスポンスを待つ必要は決してありません。クライアントがデータを変更した時には、最終的な決裁はサーバに委ねるものの、その変更はサーバの承認を待つことなく実行されます。

認証とユーザアカウント

Meteor は "Meteor Acounts" 機能を提供します。それは最高水準の認証システムです。Secure Remote Password protocol [英語版 Wikipedia, RedHatによる日本語記事] を使った安全なパスワードログインと、Facebook, GitHub, Google, Meetup, Twitter そして新浪微博を含む外部サービスとの間のインターフェイスを提供します。Meteor Acount は 開発者がアプリケーション固有のユーザを保存することができる Meteor.users コレクションを提供します。

Meteor はまたログイン, 入会, パスワード変更, パスワード紛失メールの発行といった一般的な手続きを行うフォームを提供します。"Accouts UI" はたった1行のコードで追加することができます。スマートパッケージ accounts-ui はアプリケーションで利用する外部ログインをセットアップするための設定ウィザードも提供してます。

入力データのバリデーション処理

Meteor を使うとアプリケーションのコードと publish 関数で JSON タイプの全てのデータを扱うことができます。(実際には Meteor の通信プロトコルはバイナリバッファの様な型をサポートするJSON拡張のEJSONをサポートします。) JavaScript の動的型付けによりアプリケーションで使う変数全てに厳密な型を宣言する必要はありませんが、クライアントよりアプリケーションのコードや publish 関数に渡される引数が期待したものかが保証されれば便利です。

Meteor は引数とその他の値がそれぞれに期待された型かをチェックする軽量なライブラリ (Match API) を提供します。check(username, String) や check(office, {building: String, room: Number})の様な形で利用することができます。checkは引数が期待しない形であった場合にエラーを投げます。

Meteor はまたアプリケーションのコードと publish 関数の引数をバリデートする便利な機能を提供します。

$ meteor add audit-argument-checks
上記コードを実行すると、引数に対し check を行わないアプリケーションのコードと publish 関数は例外を投げるようになります。

リアクティブプログラミング

Meteor は、データの流れと変更の伝達に主眼を当てた リアクティブプログラミング [英語版 Wikipedia] の思想を抱えています。すなわち、簡単な命令文でアプリケーションのコードがかけ、コードが参照しているデータに変更があった場合はいつでも自動的に再計算されることを意味しています。

Deps.autorun(function () {
  Meteor.subscribe("messages", Session.get("currentRoomId"));
});

上記の例 (チャットルームクライアントより拝借) はセッション変数である currentRoomId にもとづくデータの subscribe を設定しています。もし何らかの理由で Session.get("currentRoomId") の値が変更された場合は、引数として与えられた関数は自動的に実行され、古い設定を上書きする形で新しい subscribe を設定します。

この自動的な再計算は Session と Deps.autorun が互いに協力して実現しています。Deps.autorun は内部で任意の依存関係が監視された「反応可能な算出」の計算を行い、必要に応じて引数として渡された関数の再実行を行います。一方ではデータを提供する Session の様なデータ提供側は、呼び出しが行われた式やどのようなデータがリクエストされたかを記憶し、データの変更が行われなときに無効化のシグナルを送る準備をしています。

この、反応可能な評価と反応可能なデータソースのシンプルなパターンは大きな適応能力を持っています。さらに、subscribe 中断、subscribe の再度呼び出しや正しいタイミングで呼び出されているか保証を行うコードの記述から開発者を解放します。大抵の場合、Meteor を使うことで、エラーが侵入しがちなデータ伝搬クラスすべてを取り除くことができます。

下記の Meteor の機能はアプリケーションのコードを反応可能な評価として実行します。

  • テンプレート
  • Meteor.render と Meteor.renderList
  • Deps.autorun

そして変更を伝搬することができる反応可能なデータソースとして

  • Session変数
  • コレクションに対するDBクエリ
  • Meteor.status
  • subscribe ハンドラの ready()メソッド
  • Meteor.user
  • Meteor.userId
  • Meteor.loggingIn
があります。

さらに、次の stop メソッドを持つオブジェクトを返却する関数は、反応可能な評価より呼びだされた場合、算出が再実行あるいは停止された場合に停止されます。

  • Deps.autorun(ネストし-入れ子状になっ-たもの)
  • Meteor.subscribe
  • observe() そしてカーソラの observeChanges()

Meteor の実装は Deps と呼ばれるパッケージで、Deps はとても短く簡潔です。新らしく反応可能なデータソースを1から作成する際には利用できます。

ライブ HTML

HTML のテンプレート化はウェブアプリケーションの中心です。Meteor のライブページ更新機能を使うとアプリケーションの HTML を一つの応答として描画することができます、つまり生成に使ったデータの変更を追跡し自動的に更新することができます。

この選択可能な機能はどんなHTMLテンプレート提供ライブラリとでも、またアプリケーションの中の JavaScript で生成した HTML とでさえ協調が可能です。例をご覧ください。

var fragment = Meteor.render(
  function () {
    var name = Session.get("name") || "Anonymous";
    return "<div>Hello, " + name + "</div>";
  });
document.body.appendChild(fragment);

Session.set("name", "Bob"); // ページは自動的に更新します!

Meteor.render は描画を行う関数を引数としてとります。この関数は HTML を文字列として返す関数です。Meteor.render は自動的に更新される DocumentFragmentを返却します。描画を行う関数にて使用されたデータに変更があると、再実行が行われます。DocumentFragmentの中のDOMノードではその後その場でページのどの部分に挿入されているかに関わらず自分自身を更新します。それは完全なる自動です。Meteor.renderリアクティブプログラミングを使い、描画をおこなう関数がどのデータが利用されているのか判定します。

しかしながら大抵の場合、これらの関数を直接呼び出すことはなく、Handlebars や Jade の様なお好きなパッケージを使うだけで完結できます。render と renderList 関数は新たなテンプレートシステムを開発する方のために設計されています。

Meteor は必要なすべての更新と関数の実行をコードが実行されていない間にのみ実行します。この方法で開発者が任意のコードを実行している最中にDOMが変更されていない保証を提供します。ある場合にはこれとは異なる挙動が必要な場合があるでしょう。たとえば、データベースにレコードを挿入した直後、jQuery の様なライブラリを使い新しい要素が探し出せるよう、DOMの更新を強制したいかもしれません。その場合、Deps.flush を使いDOMを即座に最新の状態にすることができます。

ライブアップデートの対象のDOM要素が画面上から消え去った際には、自動的に後始末が行われます。コールバックが呼び出され、関連付けられたデータベースのクエリが停止され、更新が停止されます。このため、手打ちの更新ロジックの悩みの種となるゾンビテンプレート [ 英語版 Backbone のゾンビテンプレートについての解説記事 ] について決して思い煩うことはありません。要素を後始末より保護したい場合、イベントループに返却する前、あるいは Deps.flush を実行する前にに要素が画面上にあるか確認してください。

手打ちの場合に頭を抱える要素は他に要素の維持という問題があります。ユーザが <input> 要素にテキストを入力していると仮定して、その領域がページの再描画の対象だった場合です。<input>が再生成された時に、ユーザはフォーカス、カーソルの位置、一部を完了させていた入力内容とそのフォーマットを失う苦難を受けることとなります。

この事象もまた Meteor によって解決されます。テンプレートにて preserve を設定することで、テンプレートが再描画される際に維持される要素を指定することができます。Meteor は維持の指定がされた要素を囲う要素が再描画される場合でもこの要素を維持し、一方でその子要素を更新し、属性の変更は持ち越します。

テンプレート

Meteor では簡単に Handlebars や Jade の様なお好みの HTML テンプレート言語を Meteor のライブページ更新技術と共に利用することができます。普段テンプレートを書くのと同じように書くだけで、Meteor にリアルタイムで更新されるように扱われる様になります。

この機能を使うにはプロジェクトの中に .html 拡張子がついたファイルを用意してください。このファイルでは name 属性を持つ <template> タグを作成してくださいテンプレートをこのタグの中においてください。Meteor は事前にテンプレートをコンパイルし、クライアントに送信し、グローバルの Template オブジェクトの関数としてこれを提供します。

現段階では Meteor のパッケージとされている唯一のテンプレートシステムは Handlebars です。Meteor 開発チームに Meteor と一緒にどのテンプレートシステムを使いたいか教えてください。同時に、Handlebar ドキュメント[英語版] と Meteor Handlebars Extension [英語版] をご確認ください。

name に hello を設定したテンプレートは Template.hello 関数に様々なデータを渡し呼び出すことで描画されます

<template name="hello">
  <div class="greeting">こんにちは、{{first}} {{last}}! </div>
</template>

// JavaScript コンソールにて
> Template.hello({first: "Alyssa", last: "Hacker"});
 => "<div class="greeting">こんにちは、Alyssa Hacker!</div>"
上記の例では文字列が返却されます。テンプレートでライブHTML機能を利用しDOM要素をその場で自動的に更新するには、Meteor.render を使ってください。
Meteor.render(function () {
  return Template.hello({first: "Alyssa", last: "Hacker"});
})
 => DOM要素を自動的に更新し続けます。

テンプレートにデータを組み込む際に最も簡単な方法は JavaScript でヘルパ関数を定義する方法です。Template.[テンプレート名] に直接関数を追加するだけです。たとえば、テンプレートでは

<template name="players">
  {{#each topScorers}}
    <div>{{name}}</div>
  {{/each}}
</template>

テンプレート関数が呼び出されれる際、topScores にデータを与えるかわりに、Template.players に関数を定義します。

Template.players.topScorers = function () {
  return Users.find({score: {$gt: 100}}, {sort: {score: -1}});
};

この場合、データはデータベースのクエリに由来します。#each にデータベースのカーソラが渡された場合、新しい結果がクエリに入り込むと効率的に全自動でDOMノードの追加、移動を行うよう設定されます。

ヘルパには引数を渡すことができ、関数は現在のテンプレートのデータを this として受け取ります。

// JavaScript ファイルにて
Template.players.leagueIs = function (league) {
  return this.league === league;
};
<template name="players">
  {{#each topScorers}}
    {{#if leagueIs "junior"}}
      <div>ジュニアリーグ: {{name}}</div>
    {{/if}}
    {{#if leagueIs "senior"}}
      <div>シニアリーグ: {{name}}</div>
    {{/if}}
  {{/each}}
</template>

Handlebars 追加情報: {{#if leagueIs "junior"}} はブロックヘルパにおける入れ子構造を受け入れる Meteor の拡張にて認められる表現です。( if と leagueIs は技術的にはどちらもヘルパで、標準の Handlebars はここでは leaguesIs は実行をしません。)

ヘルパには定数を指定することもできます。
//  {{#each sections}} で呼び出してください
Template.report.sections = ["現状", "課題", "解決策"];
最後に、イベントハンドラ群のテーブルを設定する場合テンプレート関数で events 宣言を使うことができます。フォーマットはイベントマップにまとめています。イベントハンドラ内の this はイベントを発行した要素のデータコンテキストとなります。
<template name="scores">
  {{#each player}}
    {{> playerScore}}
  {{/each}}
</template>

<template name="playerScore">
  <div> {{name}}:  {{score}}
    <span class="givePoints">得点を与える</span>
  </div>
</template>
Template.playerScore.events({
  'click .givePoints': function () {
    Users.update(this._id, {$inc: {score: 2}});
  }
});
まとめると、任意のデータをテンプレートに組み込む例は下掲のようになり、データに変更が加えられた時に自動的に更新されます。さらなる議論についてはライブHTMLをご確認ください。
<template name="forecast">
  <div>今夜は{{prediction}}天気となる見込</div>
</template>
// JavaScript: 反応可能となるヘルパ関数
Template.forecast.prediction = function () {
  return Session.get("weather");
};
> Session.set("weather", "くもった");
> document.body.appendChild(Meteor.render(Template.forecast));
DOMでは:  <div>今夜はくもった天気となる見込</div>

> Session.set("weather", "寒く乾燥した");
DOMでは:  <div>今夜は寒く乾燥した天気となる見込</div>

パッケージの利用

ここまで記述してきた機能はすべて標準 Meteor パッケージとして実装されています。Meteor の並外れて強力なパッケージそしてビルドシステムによって成り立っています。ブラウザとサーバにて同じパッケージが動き、パッケージにはビルド手続きを拡張する coffeescript (CoffeeScript のコンパイル) や templating (HTML テンプレートのコンパイル) の様なプラグインを含めることができます。

meteor listを使うと利用可能なパッケージの確認、meteor add でプロジェクトにパッケージの追加、meteor remove で削除することができます。

デフォルト設定ではすべてのアプリケーションには standard-app-packages パッケージが含まれます。このパッケージはコアの Meteor スタックを構成するパッケージをひっぱり出します。事をシンプルにするため、これらのコアパッケージは meteor list の出力では隠されていますが、それらが何であるかを確認するため、standard-app-packages のソースコード) を見ることもできます (Meteor はまだ 1.0 に達していないので、リリースごとに変更されるでしょう)。もし独自のスタックを作りたい場合は、standard-app-packages をアプリケーションから削除し、継続して利用したい標準パッケージを追加して戻してください。

公式な Meteor のリリースの中のパッケージでアプリケーションに現在利用されているパッケージに加え meteor list と meteor add はアプリケーションのトップに存在する packages ディレクトリも検索します。もし非公式のパッケージを Atmosphere からダウンロードしたのであればこのディレクトリに展開してください (非公式の Meteorite ツールは効率的にこの過程を辿ります) 。packages ディレクトリはまたアプリケーションを便宜のためサブパッケージに分割する際に利用することができますーもし Meteor パッケージのフォーマットがまだドキュメント化されていなく、Meteor 1.0 の前に大幅な変更が加えるられることに勇敢であることができるのであれば。パッケージの作成をご確認ください。

名前空間

Meteor の名前空間のサポートを使うと、大規模 JavaScript アプリケーションの作成が簡単になります。アプリケーションで使うそれぞれのパッケージは、それら自身の隔離された名前空間に存在し、パッケージ自身のグローバル変数と特定の用途に向けて提供されている変数のみが参照可能です。どの様に動くかを説明していきます。 トップレベルで変数を宣言した場合、その変数をファイルスコープとするかパッケージスコープとするか選ぶことができます。
// ファイルスコープ。この変数はこのファイル1つのみから参照可能です。
// このアプリケーションあるいはこのパッケージの他のファイルからは参照不可能です。
var alicePerson = {name: "alice"};

// パッケージスコープ。この変数はこのパッケージあるいはこのアプリケーションのどのファイル
// からも参照可能です。違いは 'var' が省略されていることです。
bobPerson = {name: "bob"};

これはローカルあるいはグローバルの変数を宣言する、通常の JavaScript の文法です。Meteor はソースコードの中からグローバル変数の割り当てを探し、グローバル変数が適切な名前空間に確実に閉じ込めるラッパを作成します。

ファイルスコープとパッケージスコープに加え、エクスポートが存在します。エクスポートとは必要な時にパッケージを利用可能とする変数です。たとえば、email パッケージは Email 変数をエクスポートします。もしアプリケーションで email パッケージを使用し ( そして email パッケージのみを使用しているのなら) アプリケーションから Email が参照でき、Email.send を呼び出すことができます。多くのパッケージは1つのみエクスポートを持ちますが、いくつかのパッケージは2つもしくは3つ (たとえば、協調して動くいくつかのクラスを提供するパッケージ) 持つかもしれません。

参照可能であるのは直接使うパッケージのみです。もしパッケージ A を使用し、パッケージ A がパッケージ B を使用していた場合、パッケージ A のエクスポートのみ参照できます。あくまでパッケージ A が使用されているため、パッケージ B のエクスポートはあなたの名前空間に漏出してきません。この仕組でそれぞれの名前空間が美しく整理されます。それぞれのアプリケーションあるいはパッケージからは、それら自身のグルーバル変数と明示的に要求したパッケージの API のみが参照可能です。

アプリケーションのデバッグ中、ブラウザの JavaScript コンソールはアプリケーションの名前空間に含まれたかのように振る舞います。アプリケーションのグローバル変数とアプリケーションが直接使うパッケージのエクスポートが参照可能です。パッケージの中の変数と、中間的な依存関係 (アプリケーションにて直接的に使用されてなく、アプリケーションが使用しているパッケージが使用するるパッケージ) のエクスポートは参照不可能です。

もしパッケージの内部をブラウザのデバッガより確認したい場合、2つの方法があります。

  • パッケージコードの内部にブレークポイントを設定します。そのブレークポイントで停止している間は、コンソールはパッケージの名前空間の中にいることになります。パッケージのパッケージスコープの変数とインポート、そして停止されたファイルのファイルスコープの変数が参照可能です。
  • パッケージ hoge がアプリケーションに含まれる場合、アプリケーションが直接使用しているかどうかにかかわらず、そのパッケージのエクスポートは Package.hoge にて利用できます。たとえば email パッケージが読み込まれた場合には email パッケージを直接使用してい名前空間からであっても、 Package.email.Email.send にアクセスすることができます。
関数を宣言する際は JavaScript では function x () {} は単なる var x = function () {} の簡略形ということに留意してください。次の例を考えてください。
// これは 'var x = function ()' と同じです。つまり x() は
// ファイルスコープでこのファイル1つのみから呼び出し可能です。
function x () { ... }

// 'var' なし。つまり x() はパッケージスコープで、このアプリケーションか
// パッケージのいずれのファイルからでも呼び出し可能です。
x = function () { ... }
技術的には、アプリケーションのグローバル群は (パッケージの中とは異なり) 実際にグローバルです。アプリケーションに対し秘匿された名前空間からそれらは参照不可能です。 なぜならその事で、その空間はデバッグ中にコンソールから参照不可能になるからです。アプリケーションのグローバル群は、実際には最終的にパッケージから参照可能となります。適切に記述されたパッケージコードであれば決してこれは問題になりません (アプリケーションのグローバルはパッケージ内の宣言によって適切に隠されるからです)。もちろん、このハックを利用すべきではありませんし、将来的に Meteor はこれをチェックし利用しているのであればエラーを投げるかもしれません。

デプロイ

Meteor は最高のアプリケーションサーバです。インターネット上でアプリケーションを提供する際に必要なすべてを提供します。他にあなたが用意しなければならないのは、JavaScript、HTML そして CSS だけです。

Meteor のインフラにデプロイする

meteor deploy を使うと最も簡単にアプリケーションをデプロイできます。Meteor 開発チームがこの方法を提供しているのは、チームが個人的に常に「簡単に、創造性を奪うことなく、アプリケーションのアイデアを着想し、週末2日で具体化させ、世界から利用できる状態にする方法」を求めているためです。

$ meteor deploy myapp.meteor.com

作成したアプリケーションは myapp.meteor.com ですぐに利用可能になります。このホスト名に対しての最初のデプロイの場合は、Meteor は アプリケーション用の空のデータベースを作成します。更新版をデプロイしたい場合、Meteor は既にあるデータを持ち越し、コードのみを入れ替えます。

独自に用意したドメインにデプロイすることもできます。(ご利用のDNSサーバにて) 利用したいホスト名の CNAME に origin.meteor.com を設定し、その名前にデプロイしてください。

$ meteor deploy www.myapp.com

このサービスは Meteor の機能を体験を目的とした無料のサービスとして Meteor 開発チームにより提供されています。内部的ななベータ版やデモなどを素早く提供する際にも有用でしょう。

独自のインフラストラクチャで運用する

アプリケーションをお使いのインフラストラクチャや、Heroku の様なホスティングプロバイダ上で運用することもできます。

はじめるにあたり、下記を実行して下さい。

$ meteor bundle myapp.tgz

このコマンドは tarball の形ですべてを含んだ Node.js のアプリケーションを生成します。このアプリケーションを運用するにあたり、Node.js 0.10 と MongoDB サーバを用意する必要があります(現在の Meteor のリリースは Node 0.10.22 上にてテストを行っており、0.10.22 から 0.10.24 のみ利用することをすすめます) 。その後、アプリケーションが待機 (リッスン) する HTTP ポートと MongoDB のエンドポイントを指定し node を実行すると アプリケーションを実行することができます。もし MongoDB サーバをまだ用意していないのであれば、MongoHQ のMeteor 開発チームのパートナをおすすめすめできます。

$ PORT=3000 MONGO_URL=mongodb://localhost:27017/myapp node bundle/main.js

パッケージによっては、他の環境変数を必要とする場合もあります (たとえば、email パッケージは MAIL_URL 環境変数を必要とします) 。

現状、バンドルはそのバンドルが作成されたプラットフォーム上のみで実行可能です。異なるプラットフォーム上で実行するには、バンドルの中に含まれるネイティブパッケージをビルドしなおす必要があります。これを行うには、npm が利用可能であることを確認し、次のコマンドを実行してください。

$ cd bundle/server/node_modules
$ rm -r fibers
$ npm install fibers@1.0.0

パッケージの作成

Meteor パッケージのフォーマットは公式にはドキュメント化されていなく、 Meteor 1.0 の前に変更されるでしょう。しかし、これは毀損のパッケージのソースコードを読み、モデルに従いいく千ものパッケージを作成するあなたを止める理由にはならないでしょう。もしパッケージの作成を決意したのなら、暗中模索しなければなりませんが、いくつかの簡単なヒントをここに挙げます。
  • パッケージとは package.js を含んだディレクトリです。たとえば、 Meteor のソースツリーの packages ディレクトリ の package.js ファイルをのぞいてみてください。フォーマットと package.js というファイル名は Meteor 1.0 の前に大幅に変更されますが、機能については文法が異なっていても基本的には同様なので、管理するのは簡単でしょう。
  • パッケージは api.addfiles を使い明示的にすべてのソースファイルを一覧可能とし、そのファイルは指定された通りの順番で読み込まれます。(これはアプリケーションとはことなり、Meteor はソースファイルを探すためにディレクトリツリーを検索します。) 必要とするビルドプラグインパッケージ (coffeescript やHTMLテンプレートを利用する場合、templating) を含めるのを忘れないで下さい。
  • パッケージ ( 名前空間 をご確認ください) からのシンボルのエクスポートは on_use ハンドラの中の api.export によって実現されます。
  • エクスポートに関する奥義:エクスポートされるものは = オペレータの左側というわけではありません。エクスポートした変数にエクスポート後に新しい値を設定することはできません。a = {name: 'alice'} をエクスポートした後はいつでも a.name 変更することができますが、起動後に a にまったく新しいオブジェクトを設定した場合、 aをインポートしたパッケージからは変更が確認できなくなります。エクスポート対象は大抵の場合オブジェクトか関数なので、これが問題になることはほとんどありません。
  • パッケージは npm モジュールを利用することができます。package.js の中で必要な npm モジュールと利用したい特定のバージョンを Npm.depends を使いリストしてください。そしてパッケージの中で必要なときに Npm.require を使いモジュールをひっぱり出してください。Meteor はチームメンバ全員が常に同じコードを実行するように、100%再利用可能なビルドを作成するよう努めます。そのため npm 依存関係を特定のバージョンに固定する必要があります。裏側では、Meteor は npm shrinkwrap を使い利用する npm モジュールの中間的な依存関係のバージョンも固定します。
  • パッケージに変更された場合は毎回、Meteor は再ビルド (JavaScript ではないソースファイルのコンパイル、npm 依存関係の取得、名前空間ラッパの作成など) を行います。ビルドされたパッケージはキャッシュされ、ソースファイルの変更 (SHA1を使い追跡されます) があった場合あるいは他のビルドプラグインなどの他の依存に変更があった場合のみ再ビルドされます。再ビルドを強制する場合、ドキュメント化されていないコマンド meteor rebuild-all を使うことができますが、決して必要になることはないはずです (もしあればバグレポートを送ってください!) 。
  • ビルドプラグインは _transitional_registerBuildPlugin により作成されますが、この API は非常に流動的です。例として coffeescript パッケージを確認してください。ビルドプラグインはそれ自身で一人前の Meteor プログラムで、独自の名前空間とパッケージ依存性、ソースファイルと npm の必要条件を持っています。旧来の register_extension API は削除されました。
  • パッケージ間のゆるい依存関係を作成することも可能です。パッケージ A がパッケージ B にゆるい依存関係を持っている場合、アプリケーションが A を含むだ場合でも B は含まれる事を強制しません。しかしたとえばアプリケーションの開発者か他のパッケージにて B を含めた場合、B は A の前に読み込まれます。この仕組を使うと、他のパッケージが存在する場合に、そのオプションとして実装したパッケージを作ることや、他のパッケージを拡張することができます。ゆるい依存関係を作成するには、api.use の 3番目の引数として {weak: true} を渡してください。ゆるく依存している際にはそのパッケージのエクスポートを参照することはできません。潜在的に存在するゆるい依存関係を持ったパッケージが存在するかどうかは、Package.hoge が存在するかどうかを確認することで判別でき、エクスポートは同じ箇所から取得することができます。
  • {unordered: true} を渡すと順不同の依存関係を作ることができます。順不同の依存関係はゆるい依存関係と正反対です。A が B に順不同の依存関係を持つ場合、Aを含むとBも同様に含まれる事を強制しますが、BがAの前に読み込まれることにはつながりません。これは循環依存を解決する場合に便利かもしれません。
  • ビルドシステムはまた、パッケージの暗示をサポートします。もしパッケージ A が パッケージ B を暗示した場合、誰かがパッケージ A に依存関係を持った場合、それはパッケージ B にも同様に依存関係を持っているようになります。つまり、その人は B のエクスポートも取得することになります。api.imply を使うとこれができ、一連のパッケージを要求する standard-app-packages の様な包括的なパッケージを作成するために使用したり、accounts-base と同様に一連のパッケージを追い出し共通のコードを抽出する場合に便利です。
  • ビルドシステムはネイティブコードの思想を持ち合わせ、1つの特定のアーキテクチャ向けに設計されたパッケージが他のアーキテクチャ上で動かないようにするアーキテクチャ名のシステムがあります。たとえば、ネイティブ拡張をもつ npm パッケージを含めた場合、ビルドされた Meteor パッケージはそのアーキテクチャ専用となります、しかしそうでない場合は、Meteor パッケージのビルドは移植可能となります。

APIリファレンス

コアAPI

Publish, Subscribe API

コレクション API

テンプレート API

Methods API

セッション API

アカウント API

パスワード API

Deps API

Email API

アセット API


パッケージ リファレンス

accounts-ui


コマンドライン

Meteor 逆引きリファレンス

DB に直接レコードを追加し、クライアントの挙動を確認する方法

サーバサイドのログを確認する方法

プロジェクトにパッケージを追加する方法 (Atmosphere, mrt を含む解説)

プロジェクトに設定されたパッケージを確認する方法

Meteor サーバを他のクライアントより API サーバとして利用する方法

Meteor にてURLによってページのルーティングを行う方法

Meteor にて node.js の npm パッケージを利用する方法

Meteor は Node.js, Mongo DB* を使い、サーバサイド, クライアントサイドすべてのコードを JavaScript で書き上げることを可能としたフレームワークです。データ同期に必要な複雑な処理をフレームワークに委ね、JavaScript のみで素早くリアルタイムウェブが開発できます。

*SQLのサポートは Meteor Version 1.0 以降での実装が検討されています。

Meteor の7つの指針

原文:http://docs.meteor.com/#sevenprinciples

  • 通信対象はデータ 回線を使い送信されるのは HTML ではありません。データこそが送信され、そのデータをどのように扱うかはクライアントサイドに判断させます。
  • 言語は1つ JavaScript でクライアントとサーバ双方のインターフェイスを記述します。
  • DBはどこでも クライアントでもサーバでも変わらない透過的なAPIを使うことができます。
  • 遅延は補正 クライアントサイドでは、先読みとモデルのシミュレーションを使いまるでデータベースへの接続遅延が無いように振舞います。
  • レスポンスはフルスタックだからこそできる速度 リアルタイムをデフォルトとします、データベースからテンプレートまで、すべてのレイヤーがイベントドリブンのインターフェイスとされるべきです。
  • エコシステムが存在 Meteor はオープンソースで、既にあるオープンソースのツールやフレームワークを置き換えるのではなく組み込みます。
  • 生産性は簡潔さに比例 簡潔なプロダクトを作る際のもっともよい方法は、 実際にそのプロダクトをシンプルにすることです。素直で馴染みのある綺麗なAPIでそれを可能とします。

ロードマップ

実装予定の機能は開発チームにより下掲サイトにまとめられています。機能について予告なく変更が加えられることがあります。
http://roadmap.meteor.com/
(公式サイトでのロードマップについてのアナウンス:
http://meteor.com/faq/does-meteor-have-a-roadmap)

Meteor Kaiso(開宗) は Meteor を使った開発の際に役立つナレッジを紹介するサイトです。Meteor開発チームよりドキュメント翻訳の許可は頂いておりますが、記載されている内容は基本的に非公式でまた最新でない場合がありますのでご了承ください。また、暗示的であれ明示的であれ当サイトに記載された内容によって生じた如何なる不利益について、その内容を記載した者は一切の責任を負わない事をご承知の上ご利用下さい。

コミッタ

Meteor を使った開発に興味を持つ有志より成り立っております。翻訳したドキュメントをお寄せいただける場合は github よりプルリクエストを頂ければ幸いです。