コンパイラ

インブラウザ・コンパイル

ブラウザから実行可能になる前に、カスタムタグはJavaScriptに変換しておく必要があります。type="riot/tag"属性をscriptタグに設定するだけでOKです。例:

<!-- ここにマウント -->
<my-tag></my-tag>

<!-- インラインのタグ定義 -->
<script type="riot/tag">
  <my-tag>
    <h3>Tag layout</h3>
    <inner-tag />
  </my-tag>
</script>

<!-- <inner-tag/>は外部ファイルに定義されている -->
<script src="path/to/javascript/with-tags.js" type="riot/tag"></script>

<!-- riot.jsとコンパイラを読み込む -->
<script src="https://cdn.jsdelivr.net/npm/riot@3.13/riot+compiler.min.js"></script>


<!-- 通常のマウント -->
<script>
riot.mount('*')
</script>

scriptタグや外部ファイルには、通常のJavaScriptを結びつけた複数のタグ定義を含めることができます。

Riotは、riot.mount()が呼び出される前に、インラインまたは外部のタグを自動的にコンパイルします。

自分の<script>タグでsrcの代わりにdata-srcを使うことを好むかもしれませんが、同じリソースを2回読み込むことを避けるために、ブラウザは自動的にすべてのriotタグを事前に取得(prefetch)することを止めます。Riotは自動的にajax経由でタグを取得し、コンパイルします。

タグインスタンスにアクセスする

もしscript srcでタグを読み込もうとしていて、マウントされたタグにアクセスする必要があるなら、次のようにriot.compileで囲む必要があります:

<script>
riot.compile(function() {
  // ここでタグはコンパイルされ、riot.mountは非同期に動作する
  var tags = riot.mount('*')
})
</script>

コンパイラのパフォーマンス

コンパイルは基本的にはまったく時間がかかりません。タイマータグを30回コンパイルするのにかかる時間は、普通のラップトップで2ミリ秒です。もし、同じくらいのサイズの1000個の異なるタグからなるクレイジーなページを作ったとしても、35msしかかからないという計算になります。

コンパイラのサイズはたかだか3.2KB(gzip圧縮で1.7KB)なので、本番環境でのクライアントサイド・コンパイルも、ダウンロード量やパフォーマンスの点で心配なく使えます。

詳しくはコンパイラAPIを見てください.

デモ

プリコンパイル

プリ(事前の)コンパイルには次のようなメリットがあります:

プリコンパイルはriotコマンドで実行します。NPMから次のようにインストールできます:

npm install riot -g

riot --helpを実行して、正しく動作することを確認します。node.jsがインストールされている必要があります。

プリコンパイル版のHTMLは次のようになるでしょう:

<!-- タグをマウントする場所 -->
<my-tag></my-tag>

<!-- riot.jsのみ読み込み -->
<script src="https://cdn.jsdelivr.net/npm/riot@3.13/riot.min.js"></script>

<!-- プリコンパイルされたタグを読み込み (通常のJavaScriptです) -->
<script src="path/to/javascript/with-tags.js"></script>

<!-- 同じようにマウント -->
<script>
riot.mount('*')
</script>

使い方

riotコマンドがどのように動くか説明します:

# ファイルを現在のフォルダにコンパイル
riot some.tag

# 指定フォルダにファイルをコンパイル
riot some.tag some_folder

# 指定パスにファイルをコンパイル
riot some.tag some_folder/some.js

# 元フォルダのすべてのファイルを、指定フォルダにコンパイル
riot some/folder path/to/dist

# 元フォルダのすべてのファイルを、結合ずみの単一ファイルとしてコンパイル
riot some/folder all-my-tags.js

ソースファイルは、ひとつあるいは複数のタグを含むことができ、通常のJavaScriptを一緒に混ぜても構いません。コンパイラはカスタムタグの部分だけを変換し、ソースファイルのほかの部分はそのままにします。

詳しい情報は、riot --helpを参照してください。

監視モード

ディレクトリを監視して、ファイルが変更されたときに自動的にファイルを変換することが可能です。

# srcフォルダを監視(watch)
riot -w src dist

カスタム拡張子

タグファイルを好きな拡張子にすることができます(デフォルトの.tagの代わりに):

riot --ext html

ES6設定ファイル

設定ファイルを使用して、すべてのriot-cliオプションを簡単に保存および設定することができ、カスタムパーサーを作成することもできます。

riot --config riot.config

riotのriot.config.jsファイル:

export default {
  from: 'tags/src',
  to: 'tags/dist',
  // ファイル拡張子
  ext: 'foo',
  // htmlパーサ
  template: 'foo',
  // jsパーサ
  type: 'baz',
  // cssパーサ
  style: 'bar',
  parsers: {
    html: {
      foo: (html, opts, url) => require('foo').compile(html),
    },
    css: {
      bar: (tagName, css, opts, url) => require('bar').compile(css),
    },
    js: {
      baz: (js, opts, url) => require('baz').compile(js),
    },
  },
  // デフォルトのriot parsersオプションを拡張するために
  // 使用できる特別なオプション
  parserOptions: {
    js: {},
    template: {},
    style: {}
  }
};

Nodeモジュールとして

var riot = require('riot')

var js = riot.compile(source_string)

compile関数は文字列を受け取って、文字列を返します。

ワークフローへの組み込み

プリプロセッサ

プリコンパイルの一番美味しい部分です。カスタムタグを作るのに、好きなプリプロセッサを使うことができます。HTMLとJavaScript(訳注・CSSも)、どちらのプリプロセッサもカスタマイズが可能です。

ソースの言語は、コマンドラインの--type-t引数で指定するか、あるいは後述のようにスクリプトタグの言語を自分で定義することもできます。

<my-tag>
  <h3>My layout</h3>

  <script type="coffee">
    @hello = 'world'
  </script>
</my-tag>

CoffeeScript

# CoffeeScript プリプロセッサを使う
riot --type coffee --expr source.tag

--expr引数は、テンプレート変数(expression)の中でもプリプロセッサを使うことを指定します。”coffee”のエイリアスとして、”cs”を使うこともできます。これはCoffeeScriptで書かれたタグの例です:

<kids>

  <h3 each={ kids[1 .. 2] }>{ name }</h3>

  # Here are the kids
  this.kids = [
    { name: "Max" }
    { name: "Ida" }
    { name: "Joe" }
  ]

</kids>

each属性もCoffeeScriptになっていますね。なお、CoffeeScriptがあなたのマシンにインストールされている必要があります:

npm install coffee-script -g

EcmaScript 6

ECMAScript 6(babeljs)は、”es6”を指定することで有効になります:

ES6で書かれたタグの例:

<test>

  <h3>{ test }</h3>

  const type = 'JavaScript'
  this.test = `This is ${type}`

</test>

es6コンパイラを使用する前に、以下の手順に従ってプロジェクトを適切に構成する必要があります:

  1. babel-preset-es2015-riotをインストール
    npm install babel-preset-es2015-riot --save-dev
  2. babel-coreもインストール
    npm install babel-core -g
  3. プリセットというidを含む.babelrcファイルの作成
    { "presets": ["es2015-riot"] }

環境を設定したらタグをコンパイルすることができます:

# ES6プリプロセッサを使う
riot --type es6 source.tag

note Babelは出力にたくさんの余分なコードを生成するので、例えばbabel-plugin-external-helpers-2を使って2つの別々なステップでタグをコンパイルすることも考えられます:

# 純粋なes6のコードを使ってタグをコンパイル
riot tags/folder dist/es6.tags.js
# es6のコードを有効なes5のコードに変換
babel es6.tags.js --out-file tags.js

ここに、BabelをRiotと使った簡単なサンプルがあります。

TypeScript

TypeScriptは静的型付けをJavaScriptに追加します。--type typescriptを使って有効にします:

# TypeScriptプリプロセッサを使う
riot --type typescript source.tag

TypeScriptで書かれたタグの例:

<test>

  <h3>{ test }</h3>

  const test: string = 'JavaScript';
  this.test = test;

</test>

typescript-simpleが変換に使われます:

npm install typescript-simple

LiveScript

言語の特徴やドキュメントについては、LiveScriptを確認してください。

ソース言語は、--type-t引数で指定します:

# LiveScriptプリプロセッサを使う
riot --type livescript --expr source.tag

--expr引数はテンプレート変数についても変換することを指定します。”livescript”のエイリアスとして”ls”も使えます。LiveScriptで書かれたタグの例はこちら:

<kids>

<h3 each={ kids[1 .. 2] }>{ name }</h3>

# Here are the kids
this.kids =
* name: \Max
* name: \Ida
* name: \Joe

</kids>

each属性もLiveScriptになっています。LiveScriptがインストールされている必要があります:

npm install LiveScript -g

Pug (Jade)

HTMLレイアウトはtemplate設定オプションで、処理することができます。これは、「クリーンでホワイトスペース・センシティブなHTMLを書くための文法」pugを使った例です。

# Pug HTMLプリプロセッサを使う
riot --template pug source.tag

Pugの例:

todo
  h3 Todo
  ul
    li(each="{ items }")
      label(class="{ completed:done }")
        input(type="checkbox", checked="{ done }", onclick="{ parent.toggle }")
        = "{ title }"

  form(onsubmit="{add}")
    input(name="input", onkeyup="{edit}")
    button(disabled="{!text}")= "Add { items.length + 1 }"

  script.
    var self = this
    self.items = []
    self.disabled = true

    edit(e) {
      self.text = e.target.value
    }

    add(e) {
      if (this.text) {
        self.items.push({ title: this.text })
        this.text = this.input.value = ''
      }
    }

    toggle(e) {
      var item = e.item
      item.done = !item.done
      return true
    }

周知の通り、テンプレートにもスクリプトの種類を定義することができます。 pugが変換に使われます:

npm install pug -g

どんな言語でも

カスタムパーサーを用意することで、お好みのどんな言語でも設定できます (訳注:上記の定義済みのものの他に)。例:

function myParser(js, options) {
  return doYourThing(js, options)
}

このパーサーはコンパイラのparserオプションで渡されます。

var riot = require('riot')

var js = riot.compile(source_string, { parser: myParser, expr: true })

テンプレート変数も同様に処理したければ、expr: trueをセットします。

riot.parsers をブラウザとサーバで使う

Riotのカスタムパーサをriot.parsersプロパティで指定して、ブラウザとサーバで共通して使うこともできます。例:

riot.parsers.js.myJsParser = function(js, options) {
  return doYourThing(js, options)
}

riot.parsers.css.myCssParser = function(tagName, css) {
  return doYourThing(tagName, css)
}

一度、自分のriot.parsersを作ってしまえば、次の方法でタグをコンパイルすることができます。

<custom-parsers>
  <p>hi</p>
  <style type="text/myCssParser">
    @tag {color: red;}
  </style>
  <script type="text/myJsParser">
    this.version = "@version"
  </script>
</custom-parsers>

変換なし

デフォルトで、Riotは組込みのトランスパイラを使います。それによって、ES6的な短いメソッドの書き方を有効になります。この変換をすべて無効にしたい場合は、--type noneオプションをつけます:

# プリプロセッサなし
riot --type none --expr source.tag

AMDとCommonJS

Riotのタグは、AMD(Asynchronous Module Definition)やCommonJSとしてコンパイルすることができます。このオプションは、RiotをRequireJSのようなAMDローダ、あるいはBrowserifyのようなCommonJSローダと利用する場合に必要です。

いずれのケースでも、Riotライブラリ自体もriotとして、define/requireされていなければなりません。

# AMD と CommonJS を有効に
riot -m

AMDの例:


define(['riot', 'tags'], function (riot) {
  riot.mount('*')
})

CommonJSの例:

var riot = require('riot')
var tags = require('tags')

riot.mount('*')

もし、何かすごいものを作ったら、ぜひこちらでシェアしてくださいね!