jQuery使いがRiot.jsを使ってみた話

この記事は[Riot.js Advent Calendar 2016](http://qiita.com/advent-calendar/2016/riotjs)の13日目の記事です。

前日の方と同じようなテーマになってしまって申し訳ないです！

普段はCakePHPでのサイト構築やNode.jsでWebAPIプログラムを書いたりしてます。
フロントではjQueryしか使わない、JavaScriptフロントエンドライブラリ経験1ヶ月程度のゆるふわな感想ですので、生暖かく見守っていただければ幸いです。

# きっかけ

1. Node.jsで動いてるWebAPI(戻りはJSON)をWebブラウザでモニタリングする機能をサクッと作れないかなー
2. PHPならサクッと組めるけどNode.jsを運用しているサーバにPHPを新たに入れるのは嫌だなー
3. jQueryでDOM操作して書くのも大変だよなー(実際やったけど可読性最悪でメンテがしんどかった)
4. そうだ、JavaScriptのフロントエンドライブラリを使ってみよう！

## jQueryはすごく便利だが…

jQueryを極めたかどうかは別として、jQueryである程度コードを書けるようになると、「jQueryと水さえあれば生きていける！！」状態になります(個人の感想です)。
先日、[JavaScriptのアドベントカレンダー](http://qiita.com/advent-calendar/2016/javascript)の方に投稿した[ネイティブJavaScriptとjQueryの比較](http://qiita.com/nayuneko/items/b3ad3d6bc2687bcdb0f6)をしてみて、改めてjQueryの便利さを再認識した次第です。
しかしながらjQueryオンリーでの極度なDOM操作はしんどいものです。書き始めた時はぷよぷよで連鎖を重ねる如く、メソッドチェインを繋げることに快感を覚えるんですが、ファイルを閉じたら最後、次の日見てみたらなんじゃこりゃー！！！ってなります(ました)。jQueryのメソッドチェインは「ダイヤキュート」ぐらいに留めておき、間違っても「ばよえ～ん」を詠唱しないように心がけるべきです。

と、どうでもいい前置きは置いておいて、前々から気になっていたJavaScriptフロントエンドライブラリを使ってみることにしました。

## はじめはAngularJSを使っていた

JavaScriptのフロントエンドライブラリの二大巨頭といえば「AngularJS」と「React」のようです。ぐぐってもだいたいこの2つが上位に出てきます。一方はフルスタックのフレームワーク、もう一方はView特化型のUIライブラリ。どちらにしようか悩んだ挙句、とりあえずGoogleが作ってるし使ってみるか、ということでAngularJS(1系)を使ってみました。

なるほど、何から何まで揃っていてこりゃ便利だ。
しかしAngularJSはフルスタックのフレームワークなだけあり覚えることも多く、ツール的なものを作るには少々持て余す感じでした。
例えて言うならば、近所のコンビニにジュース買いに行くのに車で行く感じ？

正直そんな大掛かりなものは要らないですし、近所のコンビニにジュースを買いに行く程度なら徒歩かよくても自転車です。
そんなこんなで別のライブラリも試してみようということになり、色々調べているうちに以下の記事に辿り着きました。

[フロント界隈で一番イケてるのは AngularJS でも React でもなく Riot.js だという話](http://phiary.me/frontend-riot-js-no1/)

そこで、Riot.jsに興味を持ち、公式サイトの[よくある質問と答え](http://riotjs.com/v2/ja/faq/)に大変痺れるお言葉が…

> ### IE8をなんでサポートしないの?
やっと、この低品質ブラウザを無視しても大丈夫になりました。

**よくぞ言ってくれた！！この言葉を待っていた！！！！！**

というわけで、Reactをすっ飛ばしてとりあえず使ってみることにしました！

# Riot.jsのよいと思ったとこ

## 直観的に書ける

たった1ファイル(Riot.js+インブラウザコンパイラ)読み込ませるだけで、HTMLファイルが一般的なテンプレートエンジンのように早変わり。見た目上はほぼHTML+JavaScriptで、AnglureJSのような独特なディレクティブも少なく、直観的に書けるのは素晴らしいと思います。
条件分岐なら`if`、繰り返しなら`each`、イベントに至っては昔ながらの`onXXXX`(onclickなど)そのまんまですね。
`{}`で囲まれたのがテンプレート変数、この変数は[まんまJavaScript](http://riotjs.com/v2/ja/guide/#expressions)なので関数をかませたりももちろんできます。

```html
<test></test><!-- ここに出力される -->

<!-- Riot.js+インブラウザコンパイラを読み込む -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/riot/2.6.7/riot+compiler.js"></script>

<!-- 実処理内容(外部ファイルにすることも可。ここではインラインで書く) -->
<script type="riot/tag">
<test>

<!-- テンプレートとなる部分 -->
<table>
<tr each={num in numbers}>
<td>{num}</td>
</tr>
</table>
<!-- /テンプレートとなる部分 -->

// 処理となる部分:START
this.numbers = [1,2,3];
// 処理となる部分:END

</test>
</script>

<script>
  // testタグをマウントして実行
  riot.mount('test');
</script>
```

## コンポーネント指向

パーツごとに管理できるというのがいいですね。
上の例ですと、testタグがひとつのパーツであると考えられます。
しかもタグごとにHTML,JavaScript,CSSを独立したファイルとしてまとめておけるのでこれまた便利。

## シンプル イズ ベスト

Riot.jsには必要最小限の機能しかありません。標準機能で出来ることは標準機能に任せるという思想みたいです。
必要最低限の機能しかないということは、Riot.jsの自体の学習コストが低い、標準機能で実装したコードは他に使いまわせる(仮にRiot.jsを使わなくなった場合のコストも低くなるハズ)などのメリットが考えられます。

たとえば、WebAPIのデータを取得するために必要なAjax通信ですが、Riot.jsにはその機能がありません。

> え？じゃあjQueryのような外部ライブラリ入れるか、あの原始的なXMLHttpRequestで書かないとダメなの？？？

いいえ、違います。
まだ実験段階ではありますが[Fetch API](https://developer.mozilla.org/ja/docs/Web/API/Fetch_API)なんて便利な機能がいつの間にか標準APIとして提供されつつあるんですね。
→ [お疲れさまXMLHttpRequest、こんにちはfetch
](http://qiita.com/tomoyukilabs/items/9b464c53450acc0b9574)
しかもこのAPIはPromiseを返してくれるのですごく扱いやすい。
※ Promiseって慣れるとホント便利です…手前味噌ですが、
→ [約束って面倒くさい。](http://qiita.com/nayuneko/items/368c2f8b13b2b838e6a5) 

## jQueryも使えますよ

[Riot.js FAQ](http://riotjs.com/v2/ja/faq/#jquery)
ただし、DOM操作はRiot.jsに任せて、イベントデリゲートやプラグインの活用のみに限定した方がよさそうです。

# Riot.jsで惜しいなと思ったとこ

## テキスト整形機能が欲しい

ある程度作りこむとなると、AngularJSのfilter機能的なものが欲しくなります。
サーバ側で取得してきたデータをそのまま無加工で表示できればいいんですが、実際はそういうわけにもいかないことが多いと思います。(特に日時データとか)
それに加え、JavaScriptにはマトモなテキスト整形機能がありません。
せめて日付フォーマットの整形機能があってもいい気がするんですが、それすらありません。

AngularJSだと以下のようなコードで日付フォーマット整形ができます。

```js:AngularJS
{{current_date|date:'yyyy/M/d hh:mm'}}
```

Riot.jsでは自前で関数を書いて実現します。
※フォーマット出力すると大変なのでとりあえず固定フォーマットで

```js:Riot.js
<test>
{date(current_date)}
date(date_string) {
  let date = new Date(date_string);
  let y = date.getFullYear();
  let m = ("0"+(date.getMonth()+1)).slice(-2);
  let d = ("0"+date.getDate()).slice(-2);
  let h = ("0"+date.getHours()).slice(-2);
  let i = ("0"+date.getMinutes()).slice(-2);
  return `${y}/${m}/${d} ${h}:${i}`;
}
</test>
```

Viewに特化しているからこそ、こういう機能は欲しいと思いました。

## 資料が圧倒的に少ない

日本語はともかく、英語の資料もあまりないような…？
自分の検索の仕方が悪いだけ？

# 実際書いてみた

JSONを取得して表示するだけのコードです。

```html
<!DOCTYPE html>
<html>
<head>
  <title>json monitor</title>
  <meta charset="UTF-8">
  <script src="//cdnjs.cloudflare.com/ajax/libs/riot/2.6.7/riot+compiler.js"></script>
</head>
<body>
<json-monitor></json-monitor>
<script type="riot/tag">
<json-monitor>
<span if={error != ''}>{error}</span>
<table if={error == ''}>
<tr>
  <th>ID</th>
  <th>名前</th>
  <th>更新時間</th>
</tr>
<tr each={data in datas}>
  <td>{data.id}</td>
  <td>{data.name}</td>
  <td>{conv_datetime(data.modified)}</td>
</tr>
</table>
this.error = '';
// APIからJSONデータを取得
fetch('/api/hoge.json')
.then((data) => {
  return data.json();
})
.then((datas) => {
  this.update({datas});
})
.catch((error) => {
  this.update({error});
});
// 日付変換メソッド
conv_datetime(date_string) {
  let date = new Date(date_string);
  let y = date.getFullYear();
  let m = ("0"+(date.getMonth()+1)).slice(-2);
  let d = ("0"+date.getDate()).slice(-2);
  let h = ("0"+date.getHours()).slice(-2);
  let i = ("0"+date.getMinutes()).slice(-2);
  return `${y}/${m}/${d} ${h}:${i}`;
}
</json-monitor>
</script>
<script>
  riot.mount('json-monitor');
</script>
</body>
</html>
```

```json:/api/hoge.json
[{"id":1,"name":"hoge","modified":"2016-12-12 10:00:00"},{"id":2,"name":"fuga","modified":"2016-12-13 10:00:00"}]
```

これだけのコード量で完結するんだからすごい。
※実際はリクエストURLにパラメータを与えたり、ちゃんと例外処理書いたり、レイアウト整えるためにCSSとか書かないとダメですが。
JSONは(当然ですが)JavaScriptと相性いいのでサクサク書けるのはいいですね。

ちなみに自環境で動けばいいツールでしたので、レガシーなWebブラウザじゃ動かないと思います！

# さいごに

今回触れたのはRiot.jsの機能のほんの一部分です。
ルーティング処理や、イベント周りを全然追えて追えていない状況ですので、薄っぺらい内容になってしまいましたが、シンプルさが伝わってもらえれば幸いです。

ちょうど空きがありましたので、明日も引き続き書かせていただきます！