はじめてのRiot.js

手抜きタイトルのはじめてシリーズ3つ目。近頃、耳にすることの多いRiot.jsをさわってみました。

Riot.jsとは

Riot.js — A React-like user interface micro-library日本語訳

  • Reactを意識して作られた超軽量のUIライブラリ、ビュー部分(コンポーネント)に特化
  • Web componentsのように利用できる
    • HTMLの中に、JavaScriptやCSSを書く
  • 軽量、5.7KB
  • インブラウザ・コンパイルを利用することで、CDNを読み込むだけで手軽に利用できる
  • 開発元:MUUT

簡単な利用例

今回試した内容のリポジトリ。

以下手順で利用可能。

  • CDNの読み込み
  • コンポーネントの定義と読み込み
  • コンポーネントのマウント

/01/index.html

<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>一番かんたんなRiot.js</title>
    <!-- include riot.js -->
    <script src="https://cdn.jsdelivr.net/riot/2.4/riot+compiler.min.js"></script>
  </head>
  <body>
    <h1>一番かんたんなRiot.js</h1>
    <!-- place the custom tag anywhere inside the body -->
    <sample></sample>
    <!-- include the tag -->
    <script type="riot/tag" src="sample.tag"></script>

    <!-- mount the tag -->
    <script>
    riot.mount('sample', {
      who: 'Riot'
    })
    </script>
  </body>
</html>

インブラウザ・コンパイルをする場合は、riot+compiler.min.jsを読み込む。

コンポーネントの定義

/01/sample.tag

<sample>
  <h3>{ message }, {opts.who} !</h3>
  <ul>
    <li each={ techs }>{ name }</li>
  </ul>
  <script>
    this.message = 'Hello';
    this.techs = [
      { name: 'HTML' },
      { name: 'JavaScript' },
      { name: 'CSS' }
    ]
  </script>
  <style scoped>
    :scope { font-size: 2rem }
    h3 { color: #0055aa }
    ul { color: #ff5577 }
  </style>
</sample>

上記でh3やulのstyleを変更してるが、styleタグにscopedを指定してるため、コンポーネント外には適用されない。(Web componentsやAngular2と同じ感じ)

セミコロンを省略してるのは意図的らしい。(書いても問題なし)

こうなる

一番簡単なRiot.js

scriptタグの省略

  • scriptタグの記述は省略できる。
  • エディタの対応を考慮してscriptタグを記述してもよいようになっている。
  • 逆にコンポーネントをhtmlファイル内に直書きする場合は、scriptタグが入れ子になってしまうので省略する必要がある。(以下参照)
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>HTML内でコンポーネントを定義する</title>
    <!-- include riot.js -->
    <script src="https://cdn.jsdelivr.net/riot/2.4/riot+compiler.min.js"></script>
  </head>
  <body>
    <h1>HTML内でコンポーネントを定義する</h1>
    <sample></sample>
    <script type="riot/tag">
      <sample>
        <h3>{ message }, {opts.who} !</h3>
        <ul>
          <li each={ techs }>{ name }</li>
        </ul>
        <style scoped>
          :scope { font-size: 2rem }
          h3 { color: #0055aa }
          ul { color: #ff5577 }
        </style>
        this.message = 'Hello'
        this.techs = [
          { name: 'HTML' },
          { name: 'JavaScript' },
          { name: 'CSS' }
        ]
      </sample>
    </script>
    <script>
    riot.mount('sample', {
      who: 'Riot'
    })
    </script>
  </body>
</html>

疑問点

  • li内でプレフィックスなしでいきなり { name } とか書いてるけど、入れ子の場合とかでnameの所在オブジェクトを明示したい時とかどうするんだろう。

scriptで利用できるプリプロセッサ

type属性に以下の指定が使用できる。

  • es6
  • babel
  • coffee
  • livescript
  • typescript
  • vanilla

これらを利用する場合は、riot コマンドによるプリコンパイルが必要なので、riotをグローバルにインストールする必要あり。

sudo npm i -g riot
riot --help

ES2015で書いてみる

/03/index.html

<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>babel+es6で書いてみる</title>
    <!-- プリコンパイルしてるのでriot.jsのみの読み込みでOK -->
    <!--<script src="https://cdn.jsdelivr.net/riot/2.4/riot+compiler.min.js"></script>-->
    <script src="//cdn.jsdelivr.net/riot/2.4/riot.min.js"></script>
  </head>
  <body>
    <h1>babel+es6で書いてみる</h1>
    <es6test></es6test>
    <!-- babelでプリコンパイルしたjsファイルを読む -->
    <script src="es6test.js"></script>
    <script>
    riot.mount('*');
    </script>
  </body>
</html>

プリコンパイルするのでriot.min.jsのみを読み込めばOK.

/03/es6test.tag

<es6test>
  <h3>{ test }</h3>
  var type = 'ES2015'
  this.test = `This is ${type}`
</es6test>

コンパイルするにはグローバルにbabelをインストールする必要があるっぽい

sudo npm i -g babel

コンパイル。

riot 03/es6test.tag

出力先を指定する場合は以下のようにする。

riot 03/es6test.tag dist

これで03/es6test.jsが生成され、以下のよう表示される。

es6でRiot.js

ソースの変更を監視するには -w を指定する

riot -w src dist

gulpやbrowserifyやwebpackへの組み込無場合は以下参照。

htmlやcssは...

  • htmlにテンプレートエンジンのpug/jadeが利用できる
  • cssにlessが利用できる
<script type="riot/tag">  
  ...

  <style type='less'>
  </style>
</sctipt>  

お手軽ルーター

ルーターをお手軽に利用できる。

/04/index.html

<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>お手軽ルーター</title>
    <style>
      body{
        margin: 0 16px;
      }
    </style>
    <script src="https://cdn.jsdelivr.net/riot/2.4/riot+compiler.min.js"></script>
  </head>
  <body>
    <app></app>
    <script type="riot/tag">
      <app title="hoge">
        <style scoped>
        ul{
          margin: 0 -16px;
          background-color: #000;
        }
        li{
          padding: 8px 16px;
          list-style: none;
          display: inline-block;
        }
        a:visited,
        a{
          color: #fff;
        }
        </style>
        <ul>
          <li><a href='#home'>home</a></li>
          <li><a href='#blog'>blog</a></li>
          <li><a href='#contact'>contact</a></li>
        </ul>
        <content></content>
        riot.route(function(tagName) {
          tagName = tagName || 'home';
          riot.mount('content', tagName);
        });
        riot.route.start(true);
      </app>

      <home>
        <h2>Home</h2>
        <p>Lorem Ipsum is simply dummy text of the printing and typesetting industry. </p>
      </home>
      <blog>
        <h2>blog</h2>
        <p>It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. </p>
      </blog>
      <contact>
        <h2>contact</h2>
        <p>Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words, consectetur, from a Lorem Ipsum passage, and going through the cites of the word in classical literature, discovered the undoubtable source. </p>
      </contact>
    </script>
    <script>
      riot.mount('*')
    </script>
  </body>
</html>

お手軽ルーター

上記構成をシンプルに書くとこんな感じ。

<app></app>
<script type="riot/tag">
  <app>
    <a href='#home'>home</a>
    <a href='#blog'>blog</a>
    <a href='#contact'>contact</a>
    <content></content>
    riot.route(function(tagName) {
      tagName = tagName || 'home';
      riot.mount('content', tagName);
    });
    riot.route.start(true);
  </app>
  <home></home>
  <blog></blog>
  <contact></contact>
</script>
  1. riot.route(function(tagName){ ... で、hashchangeした時の処理を定義
  2. riot.mount(A, B) で、AにBの内容を割り当てる
  3. riot.route.start(true) で、hashchangeの監視開始

参考サイト

感想

Web components的な管理とかルーター機能が手軽に使えるインブラウザ・コンパイルはいいかも。 さくっと書きたい時に使いたい。