楽すぎてどうしよう。が最初の感触。まだ3時間しか触ってないけど、もうこれでいいや感が半端ない、深夜2時です。
Angularなのか、Reactなのか、2015年が明けても毎週のように新しいJSフレームワークが出る中で、もう正直どうでもよくなってませんか? でも、これは触って楽しいはず。
Riotって何?
Riotは、公式ページに
A REACT- LIKE, 2.5KB USER INTERFACE LIBRARY
とあるように、Reactを意識して作られた超軽量のUIライブラリで、ビュー部分(コンポーネント)に特化しているのが特長です。Vue.jsとかとも同類です。Riot 1.0も「超軽量」という点で、一時注目を集めました。
そのRiotが、2.0で趣向を変えてJSX的なプリコンパイルの仕組みを取り入れて、ReactとPolymerのいいとこ取りのような感じになっています。ただし、次のような大きな違いがあります。
- React: JavaScript(JSX)の中に、HTMLを書く
- Riot: HTMLの中に、JavaScriptやCSSを書く
スクリプトサイズは24分の1。Reactが優に100KBを越えるのに対して、Riotはたった5.7KB。gzip圧縮かければ2.5KB。ちなみに、Riotの開発元のMUUTは既存サイトにエンベッドして使う、フォーラムツールを作っているチームです。(Disqusみたいなやつ)
たとえばこんなコード
todo
という独自タグ(=コンポーネント)を実装するには、こんなコードになります。
<todo>
<h3>{ opts.heading }</h3>
<ul>
<li each={ items }>{ title }</li>
</ul>
<form onsubmit={ add }>
<input>
<button>Add #{ items.length + 1 }</button>
</form>
this.items = []
add(e) {
var input = e.target[0]
this.items.push({ title: input.value })
input.value = ''
}
</todo>
Reactだと、this.state.something
とか、this.props.something
が氾濫するところ、大分すっきりしてますね。HTMLの内側に、JavaScriptというのも納得感があります。
変数 opts
タグの属性として指定されたものは、コンポーネント内からopts
変数を通じてアクセスできます。Reactのthis.props
の代わりにopts
を使う感じ。<todo heading="Hello Riot!"></todo>
だったら、opts.heading
に"Hello Riot!"が入ってます。
繰り返し
Angularのng-repeat
にあたるのが、each
属性です。テンプレート部分は、mustacheに似た文法です。
items = [
{ title: '洗剤を買う' }
{ title: '牛乳を買う' }
]
のようなコレクションになっている場合、次のコードでOK。すっきり。
<ul>
<li each={ items }>{ title }</li>
</ul>
コードブロック
Reactの逆で、HTMLの中に直接JavaScript(ES6)で書くことができます。ただ、この書き方だとエディタが対応していない場合もあるので、先ほどの例は<script>
タグで明示して書くこともできます。
<todo>
<h3>{ opts.title }</h3>
<ul>
<li each={ items }>{ title }</li>
</ul>
<form onsubmit={ add }>
<input>
<button>Add #{ items.length + 1 }</button>
</form>
<script>
this.items = []
add(e) {
var input = e.target[0]
this.items.push({ title: input.value })
input.value = ''
}
</script>
</todo>
<script>
のtype属性には、現在のところcoffeescript
typescript
es6
none
が指定できるようです。
HTMLへの組み込み
先ほどのコンポーネントは、拡張子.tag
をつけて保存します(ここではtodo.tag
)。その上で、メインのHTMLから
<script src="todo.tag" type="riot/tag"></script>
として読み込みます。全体としては、次のようになります。riot.mount
でコンポーネントを利用できます。
<!doctype html>
<html>
<head>
<title>Riot todo</title>
<link rel="stylesheet" href="todo.css">
</head>
<body>
<todo></todo>
<script src="todo.tag" type="riot/tag"></script>
<script src="https://cdn.jsdelivr.net/g/riot@2.0(riot.min.js+compiler.min.js)"></script>
<script>
riot.mount('todo', {
heading: 'Hello Riot!'
})
</script>
</body>
</html>
上記は、ブラウザ上でトランスコンパイルする場合ですが、npmでインストール可能なriot
コマンド用意されていて、事前にコンパイルしておくことも可能です。すでに、
- gulp-riot - gulpプラグイン
- grunt-riot - Gruntプラグイン
- riotify - Browserifyのトランスフォーム
が用意されているので、既存の環境に組み込むのも簡単そうですね。
コンポーネントをネストする
簡単なデモが公式サイトに載っていますが、理解を深めるために、これを少し変更してみたいと思います。タスクリスト部分を別のコンポーネントにして、<li>
だった部分を<todo-item>
という新しい独自タグに置き換えてみます。
<todo>
<h3>{ opts.title }</h3>
<ul>
<todo-item each={ items.filter(filter) } title={ title } done={ done } />
</ul>
<form onsubmit={ add }>
<input onkeyup={ edit } value={ text }>
<button disabled={ !text }>Add #{ items.filter(filter).length + 1 }</button>
</form>
<script>
this.text = ''
this.items = opts.items
edit(e) {
this.text = e.target.value
}
add(e) {
if (this.text) {
this.items.push({ title: this.text, done: false })
this.text = ''
}
}
filter(item) {
return !item.done
}
</script>
</todo>
<todo-item>
の実装はこちら。<todo>
コンポーネント内で、属性として渡した値にはopts
変数からアクセスできます。Reactだとしばしば「CSSどうするの?」は問題になりますが、Riotだと、シンプルに<style>
内に書けます。その際、 todo-item <クラス名>
のような形で指定すると、コンポーネントの要素だけを指定できて便利です。
<todo-item>
<li>
<label class={ completed: done }>
<input type="checkbox" checked={ done } onclick={ toggle }>{ title }
</label>
</li>
<style>
todo-item .completed {
text-decoration: line-through;
color: #ccc;
}
</style>
<script>
this.done = opts.done
this.title = opts.title
toggle(e) {
this.done = !this.done
return true
}
</script>
</todo-item>
まとめ
ここまで、Riotのエッセンスが掴めそうなところをかいつまんで紹介してみました。でも実は、ほとんどドキュメントを読まずになんとかなってしまったことに、私自身がびっくりしています。AngularにしろReactにしろ、新しい概念を覚えてからじゃないととっつきにくいところがありますが、Riotにそういった部分はありません。(ドキュメント自体も大した量じゃないので、全部目を通しても30分もかからないくらい)
ここのところ、立て続けに新興フレームワークが世間を賑わしていますが、正直一番わくわくしました。
ほか、直近だけでもいろいろありました...。(全部は見きれてませんが)
現状の、Riotは2.0といっても、相当仕様を変えて来た所為もあってか、まだ結構しょうもないバグが含まれていたりします。さっき気づいたのだと、タグを閉じるときにスペースを空けないとバグるとか...。リリースから10日あまりで、2.0.7まで刻んできているので、その辺は推して知るべしというか。
とはいえ、サーバサイドレンダリングについても今後実装予定とのことですし、いろいろ楽しみです。引き続き、注目していきたいと思います。では。