テンプレート部分
Meteorの特徴ですが、htmlファイルは解析され、headタグの中に、実際に利用するJavaScriptのscriptタグが挿入されて、bodyタグの中身はすべて動的に作成されます。実際に生成されたHTMLのコードを見てみると分かると思います。
では、一個ずつ見てきましょう。clientフォルダにあるindex.htmlを参照すると、bodyタグの中に以下のような記載があります。{{> header }} はheaderという名前のテンプレートを挿入するという意味です。
<body> {{> header }} {{> textChat }} {{> inputBox }} </body>
この記法は、Spacebarsというテンプレートエンジンのものになります。Meteor.jsのチームが開発しているライブラリです。
index.htmlを見ていくと、name属性の値がheaderというtemplateタグがあり、その中にhtml片がありますね。これが挿入されます。
<template name="header"> <header> <nav> <div class="nav-wrapper blue lighten-1"> <a href="#" class="brand-logo">My Chatty</a> </div> </nav> </header> </template>
textChatの中身を見てみましょう。
<template name="textChat"> <div id="chat-messages"> {{#each messages}} {{> message user=user text=text timestamp=timestamp}} {{/each}} </div> </template>
こちらは、{{#each message}} という謎のものがあります。#eachはなんとなく、配列などのコレクションの要素を一個ずつ取り出し繰り返し処理に使うというイメージが付くと思います。次のmessagesですが、これは急に出てきましたね。一体どういうものなのでしょうか?
同じ階層にあるindex.jsを参照してください。こちらに答えがあります。
Template.textChat.helpers({ messages: Messages.find({}, {sort:{timestamp: 1}}) });
ここにmessagesが出てきました。ここでは、textChatというテンプレートのヘルパーを設定しており、messagesが定義されています。
Messages.find({}, {sort:{timestamp: 1}}) で、timestampでソートしてMessagesのデータを取得しています。Messagesについては、これから説明します。
クライアントとサーバーのデータの同期
Messages = new Mongo.Collection("messages");
Messagesでは、4つの要素(_id, user, text, timestamp)を持ちます。
Mongo.CollectionとあるようにMeteor.jsではMongoDBをデータベースとして利用しており、ユーザーは他のデータベースに変更できません(最近は、RethinkDBなど他のデータベースも利用できるような動きがあります)。
Meteor.publish('messages', function () { return Messages.find({}, {sort:{timestamp: -1}, limit:8}); });
Meteor.subscribe('messages');
まず、ここまで頭に入れた上で、サーバー側のデータを更新して、それが瞬時にクライアント側にも反映されることを見てみましょう。ターミナルから以下を実行してみてください。
meteor mongo meteor:PRIMARY> db.messages.insert({text: "Hello", timestamp: new Date(), user: "console"})
次にChromeブラウザの開発コンソール上で、以下を実行してみてください。
Messages.findOne({}, {sort: {timestamp: -1}}) => Object {_id: L…n._ObjectID, text: "Hello", timestamp: Thu Jul 23 2015 14:40:27 GMT+0900 (JST), user: "console"}
先ほど、サーバー側で追加したデータが追加されていることが分かります。
また、サーバーでpublishするのは、8個のドキュメントなので、クライアント側には、8個だけあります。
Messages.find().fetch().length => 8
クライアント側もサーバーと同じAPIでデータが取得できるところも素晴らしいです。クライアント側(ブラウザ)にはMongoDBはないので、その代わりにminimongoというMongoDBのすべての機能ではないですが、ほぼ互換があるin-memoryデータベースを実装することで実現しています。
minimongoもMeteor.jsのチームが開発しています。