component志向のフレームワーク!
あちこちで 「いまはReact.jsよりRiot.jsだぜ!!」 という声が聞かれるようになったので、入門したくなりました。
(いまの勢いで言えばReact.jsをちゃんとやっておくべきなんだろうけど、どうしてもJSXの記法が受け入れられない…)
さてさてRiot.jsとは。以下あたりを見ると分かりやすいです。
- Riot.js — A React-like user interface micro-library · Riot.js
- フロント界隈で一番イケてるのは AngularJS でも React でもなく Riot.js だという話 | phiary
担っている役割としてはReact.jsに近いですが、ReactがMVCで言うところのViewだと断言しているのに対して、Riot.jsはMVC(あるいはFluxとか)というよりは Webコンポーネントのフレームワーク だという文脈で説明されることのほうが多いようです。
(そういう意味ではPolymerとの比較の方が適切かも)
Webコンポーネントとはざっくり言えば、
普段HTMLとして使っているh1
とかli
とかの拡張版として、sidebar
とかglobal-menu
とかtodo-list
とか、そのWebアプリでしか使わないものも定義してしまって、その組み合わせでWebを構築しようという考え方です。
この各コンポーネントは見た目だけの意味ではなく、その部分が持っている振る舞いも内包しているので、これをほしいところにホイッと置けば万事うまく動く!というのを理想としてます。
実際触ってみた感じ、Viewだけを担うというより、全部をRiot.jsに任せたほうがきれいに組み立てられそうなイメージありました。
使ってみよう!
なんとなく世に出回ってるサンプルが、「ほら!Riotで書くとすごいよ!短いよ!!」みたいな物が多くて組み込み方が分かりづらかったので、もうちょっとすぐ動くサンプルをば。(コピペしてブラウザで開けば動くはずです)
<!DOCTYPE html>
<html lang="ja">
<head>
<title>Riot Demo</title>
</head>
<body>
<!-- ここに、TODOリストのコンポーネントができてほしい -->
<todo></todo>
<!-- 「todoタグ」の定義 (外部ファイルに書いて、srcで読み込んでもよい) -->
<script type="riot/tag">
<todo>
<ul>
<li each="{ list }">{ name }</li>
</ul>
<style>
todo li {
margin: 0.5em;
padding: 0.5em;
background-color: #eee;
}
</style>
this.list = opts.list;
</todo>
</script>
<!-- riot.js本体 -->
<script src="https://cdn.jsdelivr.net/g/riot@2.0(riot.min.js+compiler.min.js)"></script>
<!-- mount!! -->
<!-- (<todo>を書いていた部分に、定義したtodoタグの振る舞いを実際に与える その際データを渡したりする) -->
<script>
riot.mount('todo', {
list: [{
name: "やばい"
},{
name: "まじで"
},{
name: "はんぱない"
}]
});
</script>
</body>
</html>
こちらの <script type="riot/tag">
というあたりが、今回使っているtodo
というコンポーネントの定義部分になります。
HTMLの構造と、スタイルと、データをどのように取り回すかという振る舞いの部分、すべてを1箇所に書いているのが分かります。
(もっと細かい使い方は、公式読むのが一番わかります。)
compileとprecompile
上記のサンプルでは、HTMLの構造・スタイル・振る舞いがまとまったコンポーネントの記述を、riot.jsがブラウザ上でいい感じに解釈して、即実行していたのですが、この「解釈 = コンパイル」の部分を事前にやった上で読み込ませることもできます。(プリコンパイル)
定義の部分はだいたいの場合、アクセス毎に動的変化したりしないので、事前にやってしまったほうがパフォーマンスがよいのと、
プリコンパイルを使う場合は、コンポーネントの記述に様々な別の言語を用いることもできるようになっているので、言語にこだわりがあるあなたも安心です。
(自分は<``>
を書くのがもう嫌になってきたのでpug使います)
なお、コンポーネントをブラウザでコンパイルする場合と、プリコンパイル済みのコンポーネントを使う場合で、使うべきriot.jsのセットや読み込み順が変わってくるので、ちょっと注意です。
ブラウザでコンパイルする場合
<!-- mount先 -->
<todo></todo>
<!-- tagの読み込み(コンパイル前のものなので、typeは"riot/tag") -->
<script src="todo.tag" type="riot/tag"></script>
<!-- riot.js本体(コンパイラ付き) -->
<script src="https://cdn.jsdelivr.net/g/riot@2.0(riot.min.js+compiler.min.js)"></script>
<!-- mount実行など -->
<script>
riot.mount('todo');
</script>
プリコンパイルする場合
<!-- mount先 -->
<todo></todo>
<!-- riot.js本体(コンパイラなし) -->
<script src="//cdn.jsdelivr.net/riot/2.5/riot.min.js"></script>
<!-- tagの読み込み(コンパイル済のものなので、typeはjavascriptである) -->
<script src="js/tag/todo.js"></script>
<!-- mount実行など -->
<script>
riot.mount('todo');
</script>
コンパイル前のタグは、riot.jsが読み込まれる時点で文書に存在する必要があるので、riot.jsよりも 前に 、
コンパイル済みのタグは、riot.jsに含まれるメソッドに依存したjavascriptになっているので、riot.jsよりも 後に 読み込まなきゃいけないというのがミソです。
考慮しなくちゃいけないこと
さて、いい印象を多めに書いた記事でしたが、やはり「どんな状況でも使いたい!」とまではいかないかと。
以下のような懸念点がある気がするので、ベターな手段を使うようにしましょう。
-
javascriptでのレンダリングを考慮に入れない場合はからっぽのHTMLになるので、例によってSEOが激弱になる。
- サーバーサイドレンダリングもできるようなので、それができる場合はそうしましょう。
-
振る舞いのjsが膨らんできた時に、どこまでをコンポーネントに書くか、というあたりは一考が必要。肥大化したcomponentばかりになってきたら悲劇しかなさそう。
-
コンポーネントはひとつのファイルに色んな物を記述する宿命にあるので、ソースコードの検索性が落ちそう。