[翻訳] Riotjs Style Guide

  • 35
    いいね
  • 0
    コメント

De Voorhoede社のRiotJS スタイルガイドです。パブリックドメインとして公開されています。

https://github.com/voorhoede/riotjs-style-guide

Riotjsに出会い、参考になりそうなスタイルガイドをさがしていたところ、こちらのスタイルガイドを発見したので、自分の理解のために翻訳しました。jsの理解、Riotjsの理解、翻訳どれも未熟な部分があります。編集リクエスト歓迎です :bow:
Riotjsは日本語のドキュメントが少ないと言われているそうなので、何かの参考になれば幸いです。
以下翻訳


RiotJS スタイルガイド

De Voorhoede独断 チームのための RiotJS スタイルガイド

RiotJS Style Guide badge

Purpose 目的

このスタイルガイドを利用すると、RiotJS に構造を持たせることができます。

RiotJSのコードを...

  • 開発者・チームメンバーにとって理解しやすく・探しやすくします
  • IDEにとって解釈しやすく・補助しやすくします
  • すでに取り入れられているビルドツールを使いやすくします
  • バンドルされたコードを分けて管理しやすくします

このスタイルガイドはJohn PapaによるAngularJS Style Guideにインスパイアされています。

デモ

RiotJS demos はこのガイドラインに沿った実用的なサンプル集です。

目次

モジュールベースの開発
タグモジュールのネーミング
1モジュール=1ディレクトリ
*.tag.htmlを使う
タグ内で<script>を使う
タグのテンプレート変数はシンプルに
タグのオプションはプリミティブに
タグオプションを設定する
thisをtagにアサインする
タグのプロパティとメソッドを一番最初に書く
ES6風シンタックスを避ける
tag.parentは避ける
each...inシンタックスを使う
スタイルは外部ファイルに置く
タグ名をスタイルスコープとして使う
自分のタグAPIをドキュメント化する
タグのデモを追加する
タグファイルをlintする
プロジェクトにバッジをつける

モジュールベースの開発

アプリは常に、1つのことをちゃんとやる小さなモジュールで構成すること。

1モジュールはアプリ内の小さな自己完結したパーツです。RiotJSのマイクロフレームワークは特に タグ と呼ばれる ビュー・ロジック モジュール を作成するために設計されています。

Why?

小さいモジュールのほうが、学ぶのも、理解するのも、メンテナンスするのも、再利用するのも、デバッグするのも簡単だからです。自分にとっても、他の開発者にとっても。

How?

すべてのriotタグは(モジュールのように) FIRSTであるべきです。つまり、責務が1つで、独立していて、再利用できて、小さくて、テスタブルであるべきです。

もしモジュールが多くなりすぎた、あるいは大きくなりすぎたというときには、一つのことだけを行うより小さなモジュールに分割しましょう。
おおまかなやり方として、1つのタグファイルの行数を100未満にしましょう。
自分の書いたタグモジュールが独立して動くかどうか、スタンダローンデモで確かめましょう。

ヒント もしAMDかCommonJS module loaderを使っていたら、--modular フラグをつけることでタグをコンパイルできます。

# AMDとCommonJSを有効にする
riot --modular

↑ 目次に戻る

タグモジュールのネーミング

タグモジュールとは、Riotタグを含む特定のモジュールのタイプのことです。

タグモジュールは

  • 意味がある名前: 具体的すぎず、抽象的すぎない名前
  • 短い名前: 2,3語で構成された名前
  • 発音できる名前: タグについて話し合いたいので発音できる名前

であるべきです。

さらに以下の条件を満たすものであるべきです。

  • カスタム要素仕様に準拠する : 必ずハイフンを含む、予約語を使わない。
  • app- というネームスペースを使う : 非常に包括的で、それ以外だと1語になってしまう場合にも他のプロジェクトで簡単に再利用できるため。

Why?

  • 名前は、モジュールについて話し合うときに使われます。そのため、短く、意味があり、発音できる名前であるべきです。
  • タグ要素はDOMに挿入されます。そのため仕様に忠実であるべきです。

How?

<!-- recommended -->
<app-header />
<user-list />
<range-slider />

<!-- avoid -->
<btn-group /> <!-- 短いけど、発音できません。代わりに `button-group` としましょう-->
<ui-slider /> <!-- すべてのタグはUI要素なので、`ui-` に意味はありません-->
<slider /> <!--  カスタムエレメントの仕様に準拠していません-->

↑ 目次に戻る

1モジュール = 1ディレクトリ

1モジュールを構成するファイルを1つにまとめて1箇所に置きましょう。

Why?

モジュールファイル(Riotタグ、テスト、アセット、ドキュメントなど)をまとめることで、見つけやすく、移動しやすく、再利用しやすくするため。

How?

ディレクトリ名、ファイルのベース名をモジュール名と同じにしましょう。
ファイルの内容によって拡張子を変更します。

modules/
└── my-example/
    ├── my-example.tag.html
    ├── my-example.less
    ├── ...
    └── README.md

If your project uses nested structures, you can nest a module within a module.
For example a generic radio-group module may be placed directly inside "modules/". While search-filters may only make sense inside a search-form and may therefore be nested:

もしプロジェクトでネスト構造をつかっているなら、モジュールの中にモジュールをネストしてもいいでしょう。
例えば包括的な radio-group モジュールを modules/ ディレクトリの中に置きます。 search-filterssearch-form の中に置くと、こんなふうにネストされます。

modules/
├── radio-group/
|   └── radio-group.tag.html
└── search-form/
    ├── search-form.tag.html
    ├── ...
    └── search-filters/
        └── search-filters.tag.html

↑ 目次に戻る

*.tag.html を使う

Riotは タグと呼ばれる新しいコンセプトを提唱していて、 *.tag 拡張子を使うことが推奨されています。しかし、本質的にはタグはマークアップを含むカスタム要素です。その為、 *.tag.html 拡張子を使いましょう。

Why?

  • 開発者に、ただのHTMLではなくてRiotのタグ要素であると知らせるため。
  • IDEの補助を向上させるため(どのように解釈すればいいか伝えるため)。

How?

in-browser compilationの場合。

<script src="path/to/modules/my-example/my-example.tag.html" type="riot/tag"></script>

pre-compilationの場合、 custom extensionを設定します。

riot --ext tag.html modules/ dist/tags.js

Webpack tag loaderを使っている場合は、拡張子に合うように loaderを設定しましょう。

{ test: /\.tag.html$/, loader: 'tag' }

↑ 目次に戻る

タグ内で <script> を使う

Riotではタグ要素のなかに<script>タグ抜きでJavaScriptを書くことができますが、 常に<script>を使うべきです 。こちらのほうがWeb標準に近いし、開発者やIDEの混乱を防ぎます。

Why?

  • マークアップがスクリプトとして解釈されるのを防ぐため。
  • IDEのサポートを向上させるため(どのように解釈するか知らせるため)。
  • 開発者にどこまでがマークアップでどこからがスクリプトか知らせるため。

How?

<!-- recommended -->
<my-example>
    <h1>The year is { this.year }</h1>

    <script>
        this.year = (new Date()).getUTCFullYear();
    </script>
</my-example>

<!-- avoid -->
<my-example>
    <h1>The year is { this.year }</h1>

    this.year = (new Date()).getUTCFullYear();
</my-example>

↑ 目次に戻る

タグのテンプレート変数はシンプルに

Riotのテンプレート変数は100% JavaScriptです。そのため非常に強力ですが、ひどく複雑になることもあります。タグのテンプレート変数はシンプルに保ちましょう。

Why?

  • 複雑なテンプレート変数は難しすぎて読めないから。
  • テンプレート変数は他の場所で再利用できないから。コードの重複と腐敗を招く。
  • 一般的にIDEはテンプレート変数のシンタックスはサポートしていないので、オートコンプリートやバリデートができないから。

How?

複雑な表現はタグメソッドかタグプロパティに移動しましょう。

<!-- recommended -->
<my-example>
    { year() + '-' + month() }

    <script>
        const twoDigits = (num) => ('0' + num).slice(-2);
        this.month = () => twoDigits((new Date()).getUTCMonth() +1);
        this.year  = () => (new Date()).getUTCFullYear();
    </script>
</my-example>

<!-- avoid -->
<my-example>
    { (new Date()).getUTCFullYear() + '-' + ('0' + ((new Date()).getUTCMonth()+1)).slice(-2) }
</my-example>

↑ 目次に戻る

タグのオプションはプリミティブに

Riotではタグ要素の属性を使ってタグインスタンスにオプションを渡せます。タグインスタンスのオプションには opts を経由してアクセスできます。
例えば <my-tag my-attr="{ value }" />my-attrの値は、my-tagopts.myAttrを使うことでアクセスできます。

Riotでは属性を経由して複雑なJavaScriptオブジェクトを渡すことができますが、 タグオプションは出来る限りプリミティブ値にしておくこと を心がけるといいでしょう。 JavaScript primitives と関数のみを使ってみましょう。複雑なオブジェクトは避けます。

このルールには例外があります。オブジェクト(コレクションや再帰的なタグ)を使って問題を解決するときや、アプリの中でもよく知られてるオブジェクト(ウェブショップのオブジェクト)の場合です。

Why?

  • それぞれのオプションで属性を分けることで、タグが明確で表現的なAPIを持つようになるから。
  • オプションの値にJava Scriptのプリミティブ値と関数のみを使うことで、タグのAPIがネイティブなHTML(5)の要素に近くなるから。カスタム要素に直接触れるようになるから。
  • それぞれのオプション値に属性を使うことで、他の開発者もタグインスタンスに渡るものが何なのか、簡単に理解できるから。
  • 複雑なオブジェクトを渡してしまうと、オブジェクトのどのプロパティとメソッドが実際にカスタムタグで使われているのか見えなくなるから。リファクタリングしづらくなるし、コードの腐敗を招く。

How?

1つのオプションに1つのタグ属性を利用しましょう。プリミティブ値または関数を使いましょう。

<!-- recommended -->
<range-slider
    values="[10, 20]"
    min="0"
    max="100"
    step="5"
    on-slide="{ updateInputs }"
    on-end="{ updateResults }"
    />

<!-- avoid -->
<range-slider config="{ complexConfigObject }">
<!-- exception: recursive tag, like menu item -->
<menu-item>
    <a href="{ opts.url }">{ opts.text }</a>
    <ul if="{ opts.items }">
        <li each="{ item in opts.items }">
            <menu-item
                text="{ item.text }"
                url="{ item.url }"
                items="{ item.items }" />
        </li>
    </ul>
</menu-item>

↑ 目次に戻る

タグオプションを設定する

Riotではタグオプションが自分のAPIになります。堅牢で推測しやすいAPIなら他の開発者も自分の作ったタグをかんたんに使えるようになります。

タグオプションはHTMLカスタム属性を経由して渡されます。属性の値はRiotの表記 (attr="{ var }")かプレーン文字列 (attr="value")で書かないと消えてしまします。タグオプションを制御することでこれらいろいろなケースを許容することができます。

Why?

タグオプションを制御することでタグがいつでも動くようになります(セキュアプログラミング)。他の開発者が想定外の方法でタグを利用したとしても、動きます。

How?

  • オプション値にデフォルト値を入れる。
  • オプションに期待される型が入るように型変換する。
  • タグを利用する前にオプションがあるかどうかチェックする。

例えばRiotの todo exampleにデフォルト値を入れると、 item がなくても動くようになります。

this.items = opts.items || []; // default to empty list

他の場合でも動くかどうか確認しましょう。

<todo items="{ [{ title:'Apples' }, { title:'Oranges', done:true }] }"> <!-- uses given list -->
<todo> <!-- uses empty list -->

keep tag options primitive<range-slide> タグは min, max, step オプションに数値が入ります。型変換を使いましょう。

// if step option is valid, use as number otherwise default to one.
this.step = !isNaN(Number(opts.step)) ? Number(opts.step) : 1;

違う値でも動くことを確認しましょう。

<range-slider> <!-- uses default -->
<range-slider step="5"> <!-- converts "5" to number 5 -->
<range-slider step="{ x }"> <!-- tries to use `x` -->

<range-slider> はオプションとして on-slideon-end コールバックをサポートしています。オプションがあるかどうか、想定するフォーマットかどうか、事前に確認しましょう。

slider.on('slide', (values, handle) => {
    if (typeof opts.onSlide === 'function') {
        opts.onSlide(values, handle);
    }
}

違う値でも動くかどうか確認しましょう

<range-slider> <!-- does nothing -->
<range-slider on-slide="{ updateInputs }"> <!-- calls updateInputs on slide -->
<range-slider on-slide="invalid option"> <!-- does nothing -->

↑ 目次に戻る

thistagにアサインする

Riotタグ要素のコンテキストでは、 thistag instanceに紐付きます。
そのため、他のコンテキストで利用する場合にはthistagとして使えるようにしましょう。

Why?

  • thistagという変数に代入することで、他の開発者たちに tag instance と紐付けられていることを示すため。

How?

/* recommended */
// ES5: assign `this` to `tag` variable
var tag = this;
window.onresize = function() {
    tag.adjust();
}

// ES6: assign `this` to `tag` constant
const tag = this;
window.onresize = function() {
    tag.adjust();
}

// ES6: you can still use `this` with fat arrows
window.onresize = () => {
    this.adjust();
}

/* avoid */
var self = this;
var _this = this;
// etc

↑ 目次に戻る

タグのプロパティとメソッドを一番最初に書く

普通はRiotタグの中に一番最初にマークアップを書いて、その後スクリプトを書きます。 スクリプト内のtag (this)にひもづいたプロパティとメソッドは直接マークアップで参照できます。スクリプトの最初にこれらのタグのプロパティとメソッドをアルファベット順に書きましょう。1行より長いタグメソッドは別のファンクションとしてスクリプトを書いておいて、リンクさせましょう。

Why?

  • タグプロパティとメソッドをスクリプトの最初に書くことで、マークアップにタグのどの部分が使えるのかすぐ判断するため。
  • プロパティとメソッドをアルファベット順に並べることで探しやすくするため。
  • それぞれのタグメソッドとプロパティの宣言を1行にすることでひと目でタグ全体を把握できるから。
  • 関数全体はタグメソッドよりあとに記述することで、実装の詳細を隠すため。

How?

タグプロパティとメソッドをトップに書く。

/* recommended: メソッドより先にアルファベット順にプロパティを書く */
var tag = this;
tag.text = '';
tag.todos = [];
tag.add = add;
tag.edit = edit;
tag.toggle = toggle;

function add(event) {
    /* ... */
}

function edit(event) {
    /* ... */
}

function toggle(event) {
    /* ... */
}

/* avoid: don't spread out tag properties and methods over script */
/*  avoid: スクリプト全体にタグやメソッドを書くのはやめる*/
var tag = this;

tag.todos = [];
tag.add = function(event) {
    /* ... */
}

tag.text = '';
tag.edit = function(event) {
    /* ... */
}

tag.toggle = function(event) {
    /* ... */
}

mixinやobservableも最初に記述しましょう。

/* recommended */
var tag = this;
// alphabetized properties
// alphabetized methods
tag.mixin('someBehaviour');
tag.on('mount', onMount);
tag.on('update', onUpdate);
// etc

↑ 目次に戻る

ES6風シンタックスを避ける

Riotは ES6風 ショートハンドシンタックスをサポートしています。Riotは ES6風ショートハンドシンタックスのmethodName() { }this.methodName = function() {}.bind(this)にコンパイルします。これは標準的ではないので、この ES6風ショートハンドシンタックスは使うべきではありません。

Why?

  • Riotjsの提供するES6風ショートハンドシンタックスは標準的ではないので開発者を混乱させる可能性があるから。
  • タグのスクリプトは本当のES6 クラスではないのでIDEが ES6風クラスメソッドシンタックスを解釈できないから。
  • どのメソッドがタグに紐付けられているか明確にしておくべきなので、マークアップでも使えるようにするべきである。ショートハンドシンタックスはコーディングの原則である透明性や理解しやすさを曖昧にするから。

How?

methodName() { }シンタックスではなくtag.methodName =を使いましょう。

/* recommended */
var tag = this;
tag.todos = [];
tag.add = add;

function add() {
    if (tag.text) {
        tag.todos.push({ title: tag.text });
        tag.text = tag.input.value = '';
    }
}

/* avoid */
todos = [];

add() {
    if (this.text) {
        this.todos.push({ title: this.text });
        this.text = this.input.value = '';
    }
}

ヒント : ES6風シンタックスはpre-compilationのときにtypenoneにセットすることで解除できます。Disable transformation of the fake ES6 syntax

riot --type none

↑ 目次に戻る

tag.parentは避ける

Riotは nested tags を使うことで、tag.parent を通じて親コンテキストにアクセスできます。しかし、タグモジュール外からコンテキストにアクセスすることはFIRSTモジュールベースの開発に背きます。そのため、 tag.parentの利用は避けるべきです

The exception to this rule are anonymous child tags in a for each loop as they are defined directly inside the tag module.

for each loop内の匿名の子タグは、タグモジュール内に直接定義されているため例外です。

Why?

  • 親にアクセスすることで、子タグが親のプロパティを変更できるようになると、予期せぬ動作を引き起こすから。
  • タグモジュールは他のモジュールと同じように独立して動くべき。もしタグが親にアクセスすると、このルールが壊れるため。
  • もしタグが親にアクセスする必要がある場合、他のコンテキストで再利用することができなくなるため。
  • 親にアクセスすることで子タグは親のプロパティを変更できる。これは、予期せぬ動きを引き起こす可能性があるため。

How?

  • テンプレート変数を使って親から子に値を渡す。
  • テンプレート変数のコールバックを使って親タグに定義したメソッドを子タグに渡す。
<!-- recommended -->
<parent-tag>
    <child-tag value="{ value }" /> <!-- pass parent value to child -->
</parent-tag>

<child-tag>
    <span>{ opts.value }</span> <!-- use value passed by parent -->
</child-tag>

<!-- avoid -->
<parent-tag>
    <child-tag />
</parent-tag>

<child-tag>
    <span>value: { parent.value }</span> <!-- don't do this -->
</child-tag>
<!-- recommended -->
<parent-tag>
    <child-tag on-event="{ methodToCallOnEvent }" /> <!-- use method as callback -->
    <script>this.methodToCallOnEvent = () => { /*...*/ };</script>
<parent-tag>

<child-tag>
    <button onclick="{ opts.onEvent }"></button> <!-- call method passed by parent -->
</child-tag>

<!-- avoid -->
<parent-tag>
    <child-tag />
    <script>this.methodToCallOnEvent = () => { /*...*/ };</script>
<parent-tag>

<child-tag>
    <button onclick="{ parent.methodToCallOnEvent }"></button> <!-- don't do this -->
</child-tag>
<!-- allowed exception -->
<parent-tag>
    <button each="{ item in items }"
        onclick="{ parent.onEvent }"> <!-- okay, because button is not a riot tag -->
        { item.text }
    </button>
    <script>this.onEvent = (e) => { alert(e.item.text); }</script>
</parent-tag>

↑ 目次に戻る

each ... inシンタックスを使う

Riotでは様々なloop表記が使えます。配列の要素(each="{ item in items }")、オブジェクトのキーと値(each="{ key, value in items }") 、そしてショートハンド (each="{ items }")表記です。このショートハンドは混乱を招くでしょう。そのため each ... in シンタックスを使うべきです

Why?

Riotは新しいタグインスタンスをeachのループを使って作成します。
ショートハンド表記を使っていると、現在のitemのメソッドやプロパティは現在のタグインスタンス (ローカルの this) に紐付けられます。そのためマークアップを見ても中身が明らかではなく混乱のもととなります。そのためeach ... in シンタックスを使うべきです

How?

each="{ items }" シンタックスの代わりに、 each="{ item in items }"each="{ key, value in items }" を使いましょう。

<!-- recommended: -->
<ul>
    <li each="{ item in items }">
        <label class="{ completed: item.done }">
            <input type="checkbox" checked="{ item.done }"> { item.title }
        </label>
    </li>
</ul>

<!-- recommended: -->
<ul>
    <li each="{ key, item in items }">
        <label class="{ completed: item.done }">
            <input type="checkbox" checked="{ item.done }"> { key }. { item.title }
        </label>
    </li>
</ul>

<!-- avoid: -->
<ul>
    <li each="{ items }">
        <label class="{ completed: done }">
            <input type="checkbox" checked="{ done }"> { title }
        </label>
    </li>
</ul>

↑ 目次に戻る

スタイルは外部ファイルに置く

開発者の都合上、Riotはタグ要素のスタイルをネストされた<style> タグの中で定義してもよいことになっています。これらのスタイルはタグ要素にscopeされるので、Riotではカプセル化できません。その代わりにRiotはタグからスタイルを抽出してruntime上でドキュメントに注入しています。Riotはカプセル化の機能がないのでネストされたスタイルをJavaScriptにコンパイルします。 スタイルは外部ファイルにおくべきです。

Why?

  • 外部スタイルシートはブラウザーでハンドルされ、Riotやタグファイルからは独立する。こうすることによって、JavaScriptでエラーが起こってロードされない場合もスタイルが適用されるから。
  • 外部スタイルシートではpre-processor(Less、Sass、PostCSSなど)を利用でき、すでに使っているビルドツールを使うこともできるから。
  • 外部スタイルシートならminifyでき、保存とキャッシュを別にすることができ、パフォーマンスを向上させることができるため。
  • Riot表記はネストされた<style>では利用できないのでメリットがないから。

How?

タグとマークアップに紐づくスタイルは別のスタイルシートファイルに切り出し、モジュールディレクトリ内のタグファイルのとなりに配置する。

my-example/
├── my-example.tag.html
├── my-example.(css|less|scss)    <-- external stylesheet next to tag file
└── ...

↑ 目次に戻る

タグ名をスタイルスコープとして使う

Riotタグ要素はカスタムエレメントで、スタイルスコープのルートとしてもよく使われています。対照的に、モジュール名はCSSのクラス名として使えます。

Why?

  • タグ要素でスタイルをスコープすることで、予測しやすくなり、スタイルがタグ要素の外に流出することを防ぐから。
  • moduleディレクトリと同じ名前を使うことでRiotタグとスタイルルートが一緒に使われていることが理解しやすくなるから。

How?

タグ名をセレクタ、親セレクタ、プレフィックスとして使う。(CSS命名規則に合わせる)

/* recommended */
my-example { }
my-example li { }
.my-example__item { }

/* avoid */
.my-alternative { } /* not scoped to tag or module name */
.my-parent .my-example { } /* .my-parent is outside scope, so should not be used in this file */

注意: もしRiotタグにdata-is= (introduced in v2.3.17)を使っている場合は、 .my-example の代わりに [data-is="my-example"] をCSSセレクターとして使えます。

↑ 目次に戻る

自分のタグAPIをドキュメント化する

Riotタグのインスタンスはアプリケーション内部のタグ要素を使って作られています。このインスタンスはカスタム属性を通して設定されています。他の開発者がタグを利用するときのために、これらのカスタム属性 (つまり、タグのAPI)をREADME.md に記載しておきましょう。

Why?

  • ドキュメント化することで、コードを見なくてもモジュールについてのハイレベルな理解ができるから。モジュールにアクセスしやすく、使いやすくなる。
  • タグのAPIは設定されたカスタム属性のあつまりであって、タグを開発しない利用者にとって一番興味がある部分だから。
  • ドキュメント化することによってAPIを正式なものにし、タグを変更するときにどの機能に互換性をもたせるべきか他の開発者に知らせることができるから。
  • README.mdは最初に読むべきドキュメントのファイル名のデファクトスタンダードで、Github, Bitbucket, Gitlabなどのコードホスティングサービスではソースのディレクトリを開くとデフォルトで README.mdを表示し、この構成はmoduleディレクトリでも同じだから。

How?

タグのモジュールディレクトリに README.mdを追加する。

range-slider/
├── range-slider.tag.html
├── range-slider.less
└── README.md

READMEファイルの中でmoduleの機能と使い方を説明します。
タグモジュールの場合はAPIであるカスタム属性について説明すると便利です。

# Range slider

## Functionality

The range slider lets the user to set a numeric range by dragging a handle on a slider rail for both the start and end value.

This module uses the [noUiSlider](http://refreshless.com/nouislider/) for cross browser and touch support.

## Usage

`<range-slider>` supports the following custom tag attributes:

| attribute | type | description |
| --- | --- | --- |
| `min` | Number | number where range starts (lower limit).|
| `max` | Number | Number where range ends (upper limit).|
| `values` | Number[] *optional* | Array containing start and end value.  E.g. `values="[10, 20]"`. Defaults to `[opts.min, opts.max]`.|
| `step` | Number *optional* | Number to increment / decrement values by. Defaults to 1.|
| `on-slide` | Function *optional* | Function called with `(values, HANDLE)` while a user drags the start (`HANDLE == 0`) or end (`HANDLE == 1`) handle. E.g. `on-slide={ updateInputs }`, with `tag.updateInputs = (values, HANDLE) => { const value = values[HANDLE]; }`.|
| `on-end` | Function *optional* | Function called with `(values, HANDLE)` when user stops dragging a handle.|

For customising the slider appearance see the [Styling section in the noUiSlider docs](http://refreshless.com/nouislider/more/#section-styling).

↑ 目次に戻る

タグのデモを追加する

それぞれ違うコンフィグで表示させたデモを *.demo.html ファイルとして追加することで、タグがどのように使われるかを示します。

Why?

  • タグのデモでモジュールがそれ単体で動くことを証明するため。
  • タグのデモは開発者がドキュメントやコードを読み込む前のプレビューになるから。
  • デモをすることでタグを使う可能性のあるコンフィグやバリエーションに気づくため。

How?

モジュールディレクトリに *.demo.htmlファイルを追加する。

city-map/
├── city-map.tag.html
├── city-map.demo.html
├── city-map.css
└── ...

デモファイルの中身:

  • runtime内でもコンパイルするために、 riot+compiler.min.js をインクルードする
  • タグファイル(e.g. ./city-map.tag.html)をインクルード
  • demo タグ(<yield/>)を作り、デモ内に埋め込む(そうしないとオプション属性が効かないので)
  • <demo> タグの中にデモの中身を書く
  • おまけに <demo> タグにaria-labelを追加し、タイトルバーとして使う
  • riot.mount('demo', {})を使ってイニシャライズする

city-tagモジュール内のデモ例:

<!-- modules/city-map/city-map.demo.html: -->
<body>
    <h1>city-map demos</h1>

    <demo aria-label="City map of London">
        <city-map location="London" />
    </demo>

    <demo aria-label="City map of Paris">
        <city-map location="Paris" />
    </demo>

    <link rel="stylesheet" href="./city-map.css">

    <script src="path/to/riot+compiler.min.js"></script>
    <script type="riot/tag" src="./city-map.tag.html"></script>
    <script>
        riot.tag('demo','<yield/>');
        riot.mount('demo', {});
    </script>

    <style>
        /* add a grey bar with the `aria-label` as demo title */
        demo:before {
            content: "Demo: " attr(aria-label);
            display: block;
            background: #F3F5F5;
            padding: .5em;
            clear: both;
        }
    </style>
</body>

注意: ビルドスクリプトを使うともっときれいになります。

↑ 目次に戻る

タグファイルをlintする

Linterはコードの一貫性を保ち、シンタックスエラーをトレースする補助をしてくれます。いくつか追加の設定をすればRiotタグファイルもlintできます。

Why?

  • タグファイルをリントすることですべての開発者がおなじコードスタイルになるから。
  • tagファイルをリントすることで手遅れになる前にシンタックスエラーに気づけるから。

How?

Linterが *.tag.html ファイルのスクリプトを抽出するようにします。スクリプトは<script> タグの中に書き込みタグ表現をシンプルにします(そうじゃないとLinterがわかってくれません)。Linterでグローバル変数の riot とタグのopts を設定しましょう。

ESLint

ESLintでタグファイルからスクリプトを抽出するにはESLint HTML pluginが必要です。
modules/.eslintrcでESLintを設定しましょう(IDEも解釈できるように)。

{
    "extends": "eslint:recommended",
    "plugins": ["html"],
    "env": {
        "browser": true
    },
    "globals": {
        "opts": true,
        "riot": true
    }
}

Run ESLint
ESLintを実行します。

eslint modules/**/*.tag.html

JSHint

JSHint はHTMLをパースし (--extra-ext を使います) 、スクリプトを抽出します(--extract=auto を使います)。

modules/.jshintrcでJSHintを設定しましょう(IDEも解釈できるように)。

{
    "browser": true,
    "predef": ["opts", "riot"]
}

Run JSHint
JSHintを実行します。

jshint --config modules/.jshintrc --extra-ext=html --extract=auto modules/

Note: JSHint does not accept tag.html as extension, but only html.
ヒント: JSHintはhtmlのみを拡張子として認識し、tag.html拡張子は認識しません。

↑ 目次に戻る

プロジェクトにバッジをつける

このガイドへのリンクは RiotJS Style Guide badge を使ってください。

RiotJS Style Guide badge

Why?

他の開発者に自分のプロジェクトがRiotjsスタイルガイドに従っていることを示すため。このガイドがどこにあるか教えるため。

How?

プロジェクトにバッジを貼り付けてください。マークダウンだとこう。

[![RiotJS Style Guide badge](https://cdn.rawgit.com/voorhoede/riotjs-style-guide/master/riotjs-style-guide.svg)](https://github.com/voorhoede/riotjs-style-guide)

htmlだとこう。

<a href="https://github.com/voorhoede/riotjs-style-guide">
    <img alt="RiotJS Style Guide badge"
         src="https://cdn.rawgit.com/voorhoede/riotjs-style-guide/master/riotjs-style-guide.svg">
</a>

↑ 目次に戻る

この投稿は Riot.js Advent Calendar 201616日目の記事です。