MeteorでWebアプリを書いてみて気づいたポイント
Othello by Meteor: Webアプリ初心者が5時間弱かけて書いたもの
https://github.com/nebuta/MeteorOthello
公式ドキュメントhttp://docs.meteor.comは英語だが短いので全部読み通すのもさほど苦ではないだろう。ドキュメントを読みながら、meteor create --example todosで作られるToDoアプリを読みながら改変していくのがわかりやすくて良さそう。
clientとserverの二つのフォルダに、それぞれのコードを置き、共通のコードはそれ以外の部分に置けばよい。Meteor.is_server()を使えばコード内で環境を判別可能。
JSに書く大まかな処理の流れ
- Collection(データベース)をサーバーとクライアントにそれぞれnew Meteor.Collection("同じ名前")で作る。
- サーバー側のコードで、クライアントに対してデータベースをMeteor.publish()でパブリッシュする。
- クライアント側のコードで、サーバーのデータベースをMeteor.subscribe()で購読する。
- セッションの状態は、Session.set(), Session.get()で管理する。
- このSessionの意味は、まだイマイチ理解していない。
- 初期化コードはMeteor.startup()の中に書く。
- ただし、Collectionの作成やsubscribe, publishはstartup()の中ではなく、トップレベルの地の文で行う。このあたりの違いがちょっとよく分からない。
HTMLに書く大まかな処理の流れ
.htmlの拡張子がついているが、正式なHTMLではない。ルート要素のはなく、
ととがルートに並ぶ。{{ }}の中身がテンプレートとして置換される。Handlebars(http://handlebarsjs.com/)というテンプレートエンジンを使っているそうだ。あまりパワフルではなく、適当に選んだっぽい感じがする。入れてほしいエンジンを教えてくれとかMeteorの公式docにも書いてあるし。othello.html
<head> <title>Othello</title> </head> <body> {{> board}} {{> tools}} </body> <template name="board"> <div id="board"> {{#each cells}} {{> cell_item}} {{/each}} </div> </template> <template name='cell_item'> <div class='cell {{piece}}' style='{{style}}'> <span class="piece"> </span> </div> </template> ....(省略)
{{> board}}という記述は、nameがboardであるtemplateで置換される。テンプレートは入れ子にでき、最終的にJavaScriptの関数が呼ばれ、そこで返された文字列がHTMLとして代入される。
たとえばcell_itemテンプレートの中の{{piece}}は、Template.cell_item.pieceというJavaScriptの変数に代入された関数が呼ばれる。
Template.cell_item.piece = function(){ return {'w':'white','b':'black','n':'none'}[this.piece]; }
ここでのthisは何か。cell_itemテンプレートは親テンプレート"board"の中の{{#each cells}}ブロック内で呼ばれている。cellsはTemplate.board.cellsでCells.find()が返すイテレータ(Meteor.Collection.Cursor)であり、thisはそのイテレータ各要素。
Template.board.cells = function(){ return Cells.find(); }
CSS
普通に書くのみ。
データベースの使い方
基本的には標準的なMongoDBのようだが、初めて使ったので覚え書きのためにいくつか例を書いておく。
新規作成して要素追加
Cells = new Meteor.Collection('cells'); Cells.insert({board_id: 'b1',x:x,y:y,piece:'n'});
検索して該当要素の変更をモニター
if(stopHandle) stopHandle.stop(); stopHandle = Boards.find({black: true, white: true}).observe({ added: function(){ Boards.update({},{$set: {ready: true}}); } });
updateメソッドは$setの中にハッシュを入れ子にすることで、他のキーを変更せずにpieceだけを変更できる。そうでないと当該要素の他のキーを消してしまう。
レコードの全削除
Cells.remove({});
まとめ
Meteorに関して以上のことを理解すれば後は速い。自分の場合、テンプレート周りとデータベース周りで若干ハマったような記憶がある。それとHTMLで盤面を書く書き方。最終的に@tkihira氏(http://twitter.com/tkihira)の「1時間でオセロを作る動画」http://www.nicovideo.jp/watch/sm8391299のやり方で、position: absoluteに設定して座標を設定する方法にした。それと、石が置けるかどうかの判定も@tkihira氏のアルゴリズムを使った。ありがとうございます。もしかしてと思いながら、その動画を流しながら書いていたのだが、1時間ではさすがに出来ず、4回再生+αでどうにか終わった。やっぱりHTMLのレイアウトの勉強がもっと必要だな。どこかに体系的に学べるリソースがないだろうか...。Webアプリの経験もRoRの経験もほとんどないので既存の技術との比較はあまりできないが、リアルタイムWebアプリが簡単に作れるとなると、こんな事が出来たら、みたいな漠然としたアイデアはいろいろ湧いてくるな。