いまさらBackbone.jsでSPAぽいものを作ったので
反省と学びをメモしておきます。
リポジトリは、
ご参考まで。
2014/04/24現在、Backbone.Marionetteで作りなおしました。
作ったものの概要
簡単なポケモン図鑑です。
布団の中でWiFi対戦に潜ってて、「そもそもコイツ何タイプ・・?」とか、「コイツって耐久あるんやっけ?」とかなったとき、
対戦wikiをGoogleで検索してる時間はないけどサクッと知りたい・・!っていう個人的ニーズのもと作られました。
- あいうえおから検索
- 図鑑No順の一覧から検索
すると、種族値と特性とタイプ相性がわかります。
それだけ。
実装的には、
- Backbone.jsでできてる
- Require.jsで依存管理
- いわゆるSPA
- JSTはプリコンパイル
- 1ソースでバイリンガル対応
- マスタデータはLocalStorageに貯めてる
- フラットデザイン風
やってみたかった感満載の一品となっております。
所感つらつら
- Backboneは確かに背骨
- でも背骨だけでは何も成せない
- underscoreとjQueryはほんとにすごい
- Require.jsは個人的に賛否両論
- 規模はどうあれ結局、設計がイノチ
Backbone.jsの勘所
自分の作りたいものと比較して、コレだ!っていうサンプルが見つからなかったのが辛かったです。
よって、出来上がったコードも正解ではないんやろなーって箇所がちらほらいます。
いちおう、今後のために書き留めておきたいBackboneのノウハウ的なのは以下です。
Backbone.Routerが起点になる
さて、どこからコード書いていこうかってなったときに、ここから書き始めると良いと思いました。
いわゆるエントリーポイントってやつですかね。
ただこのRouterを起点に据えてしまうと、このアプリ全体!って概念と競合する気がするので、しっかり決めなきゃな感じ。
あとは今回みたく、Routingの度にViewのインスタンス作るのか、最初に全部作っちゃって、表示の切替だけにするのか、とか。
今となっては、
- Viewは最初に全部インスタンスつくる
- RouterはViewの表示の切替メソッドだけ叩く
- DOMの更新が必要なViewは、そこを勝手に更新する
みたいなのが良かったかなーと思ったりも。
Collection.fetchを保証してからViewを
なんだかしかCollection的なものをサーバーサイドとやりとりするのであれば、これは重要だと思われます。
Ajaxでデータ取ったりしてると、Viewの切り替え時にはまだレスポンスが返ってきてなくて白い画面が・・みたいのは回避したいので。
そもそもRouterでViewを切り替える部分で、Collectionのfetchなりをフックしてあげる必要がありそうです。
幸いな事に、 Backbone.Collection.fetch は jqXHR を返してくれるので、こういうことができました。
myCollectionFetch.done(function() { new MyView({ el: '#my-view', collection: myCollection }); });
Collection.fetch を自作する場合は、$.Deferred()でも使って、同じ感じになるようにすれば良い感じです。
背骨の限界
あと一歩的な意味で、物足りなさを感じる箇所がちらほら。
onBeforeRouteみたいなイベントも欲しくなってくるし。
Viewの切り替えと同時に document.title を書き換えるとか、定型化するリンクのイベント管理とか、
逐一Viewに実装していくとなんだかなーみたいなやつらのやり場がなかったり。
あと1Route1Viewだったのでなんとかなってますが、コレは増えてきたら破綻するニオイがします。
まあこのあたりは、Backbone経験値を積めばなんとかなりそう(慣れそう)です。
Marionetteとかはそういうのを解決してくれるんやろうか。
最後までわからなかったこと
一応メモ。
Backbone.history.navigateどこまでやるか
上述のとおり、定型化するリンクをViewに実装するたびに、 events に記述を増やすのがどうもなーと思ってまして。
aタグのhrefに直接 #hoge って書いても動くので、もうそれでいいのでは・・と何度も心が折れそうになりました。
いい落とし所はどこなんでしょうか。
Collectionとうまくやる方法
これはなんか見落としてるだけな気もするんですけど・・。
Backbone.Collection は Underscore.jsのいくつかのメソッドが使えます!的なことが書いてますが、
myCollection.comparator = 'name'; myCollection.sort(); // OK myFilteredCollection = myCollection.filter(); myFilteredCollection.comparator = 'id'; myFilteredCollection.sort(); // NG: myFilteredCollection は、もはやBackbone.CollectionではなくBackbone.Modelのつまった配列
これはそういう仕様なのでしょうか。
あと先日記事にしたコレ。
うーん、わからない。
濁点含む文字列のうまいsort
これはなんかそもそもですけど・・。
var arr = ['カイロス', 'ガブリアス', 'カメックス']; arr.sort(); // ["カイロス", "カメックス", "ガブリアス"] ってなるけど元のままでいてほしい
これ、どうしたらいいんかなー。
unicodeとかに分解して云々すればいいんかな・・。
Handlebarsのプリコンパイルがコケる
いろいろ調べたのですが、結局Underscoreのテンプレに乗り換えることで解決としました。
grunt-contrib-handlebarsが悪いとか、ランタイムのバージョンあげればなおるとか、
なんかいろいろ調べれば出てくるものの、結局どれもこれも効果がなく!
たぶんもうあのヒゲは使わないと思います・・・。
おわりに
ページ構成としてはたった4ページ。
機能も全然ないはずですが、それでも結構たいへんでした。
年明けからはじめたプロジェクトなので、製作期間はだいたい2ヶ月くらい。
(もっと余裕のある仕事に就いてればもっと早かったでしょうね・・・。)