Riot.js 2.0 を触ってみた — まだReactで消耗しているの? を読んで Riotjs のいいところまだあるんやで!とおもったので補足がてらいくつか書きます。主にコンパイラまわりです。
ファーストインプレッションでめっちゃ面白かったので、gulp-riot
作ったりとかモリモリと触り続けて PR 送ったりしていたら今、みたいな感じです、よろしくお願いします。
コンパイル後のファイルがめっちゃ単純
上の記事でも書かれているんですが、Riot には独自のシンタックスを持っています。
<todo>
<!-- layout -->
<h3>{ opts.title }</h3>
<ul>
<li each={ item, i in items }>{ item }</li>
</ul>
<form onsubmit={ add }>
<input>
<button>Add #{ items.length + 1 }</button>
</form>
// logic
this.items = []
add(e) {
var input = e.target[0]
this.items.push(input.value)
input.value = ''
}
</todo>
こんなん。で、これを JavaScript にコンパイルして使うんですが、コンパイルされるとどういう JS が出てくるかというと
riot.tag('todo', ' <h3>{ opts.title }</h3> <ul> <li each="{ item, i in items }">{ item }</li> </ul> <form onsubmit="{ add }"> <input> <button>Add #{ items.length + 1 }</button> </form>', function(opts) {
this.items = []
this.add = function(e) {
var input = e.target[0]
this.items.push(input.value)
input.value = ''
}.bind(this);
});
こんなんです。読みくだくまでもなく、
riot.tag(tagName, htmlTemplate, callback);
という構成になっていることが分かります。それじゃあ Altjs とか HTML template とめっちゃ相性いいやん〜!とおもって HTML 部を Jade で書いてスクリプトを CoffeeScript で書ける e-jigsaw/roister っていう AltRiot? を作って試用してみていました。すると数日後、本家の方で CoffeeScript がコンパイルできるようになってるじゃあないですか!それじゃあ Jade も、と Jade もプリコンパイルできるように PR 送ったらマージされたので、オフィシャルのコンパイラで Jade + CoffeeScript の組み合わせでコンポーネントが書けます。ワーイ!
Jade + CoffeeScript で書くと上のコードはこう書けます
todo
h3 { opts.title }
ul
li(each='{ item, i in items}') { item }
form(onsubmit='{ add }')
input
button Add { items.length + 1 }
script(type='text/coffeescript').
@items = []
@add = (e)=>
input = e.target[0]
@items.push input.value
input.value = ''
簡潔明瞭!読みやすい!
まあコンパイルといってもコンパイル後の JS が単純なので、正規表現でモリモリ HTML と JS を分離して各々ぶっこんでいくだけの簡単なコンパイラなのでこちらも軽量です。
ちなみに、CoffeeScript だけではなく 6to5 を使えば ES6 のシンタックスで書けますし、TypeScript でも書けます。
Browserify を外せる
React と比較するのは気が引けるのですが、React だとどうしても Browserify でゴニョゴニョする必要がある気がします(ES6 module はやくなんとかなってくれ!!)。一方、1.でも書いた通り Riot はコンパイル後のファイルが単純なので concat するだけで実用できます。
なので、拙作の e-jigsaw/gulp-riot を使えば
gulp = require 'gulp'
riot = require 'gulp-riot'
concat = require 'gulp-concat'
gulp.src 'components/*.tag'
.pipe riot()
.pipe concat 'app.js'
.pipe gulp.dest 'build'
というような感じで Browserify を挟まずに gulp にだけ乗っかってコンパイルができます。
サンプルサイト
Riotjs を使って http://emo.jgs.me/ っていうサイトを作ってみています。リポジトリは https://github.com/jgsme/emo にあります。
こんな感じで絵文字を引けるサービスです。似たようなやつが他にもあるんですが、日本語でも引けるものがないので作ってみました。まだ全然キーワードが足りてないので https://github.com/jgsme/emo/blob/master/src/data/emojis.custom.ja.json を適当に編集して PR 送ってもらえると反映できるのでもしよろしければ。
上に書いてきたことをだいたい試しているので、コードに目を通してもらえるとなんとなく分かってもらえるとおもいます(たぶん)。
おわりに
さて、先の記事でも触れられていた「タグを閉じるときにスペースを空けないとバグる」は僕もしっかりと踏みました。Riot のタグだと <input type='text'>
って書いとけば問題なく動くんですが、Jade から HTML を出力してる関係でどうしようもなかったので直して PR 送りました。ただ、メインのコミッタの tipiirai が NY に旅行中らしいので一週間くらい取り込まれなさそう...。あと、dev branch ではもう修正されてるっぽいので取り込まれないかもしれないです。他にもまだ issue はぼちぼち立ってる(CLI で .tag
の拡張子しかコンパイルされないとか)んですが、今のところそれ以外で困ったりしたところはあんまりないです。
また、Flux の Riot 版のサンプル実装があります。-> https://github.com/jimsparkman/RiotControl/blob/master/riotcontrol.js まだこの辺は全然触ってないのでいずれ取り入れてみようかと考えています。
Web Components と VirtualDOM という観点ではまさに Polymer と React を足して2で割ったような感じかとおもうんですが、テンプレートの書き味なんかからも Vue.js にも近いんじゃないかと考えています。雑な言い方をすると、Vue の component の template に methods やらなんやらを詰め込んだ感じだとおもいました。なので、Vue や React を経てきているひとには敷居が結構低いんじゃないかと。
ロードマップは https://muut.com/riotjs/faq.html#any-future-plans- に書いてあります。ブラウザベースコンパイルはもう実装されているので、Riot のシンタックスのコードであればプリコンパイルすることなく使うことができます。そして、目玉はやっぱりサーバサイドレンダリングですね。
というわけで、軽量 VirtualDOM, Web Components 実装として Riotjs とてもおすすめです。