De Voorhoede社のRiotJS スタイルガイドです。パブリックドメインとして公開されています。
Riotjsに出会い、参考になりそうなスタイルガイドをさがしていたところ、こちらのスタイルガイドを発見したので、自分の理解のために翻訳しました。jsの理解、Riotjsの理解、翻訳どれも未熟な部分があります。編集リクエスト歓迎です
Riotjsは日本語のドキュメントが少ないと言われているそうなので、何かの参考になれば幸いです。
以下翻訳
RiotJS スタイルガイド
De Voorhoede独断 チームのための RiotJS スタイルガイド
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-filters
を search-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?
<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-tag
に opts.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-slide
と on-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 -->
this
をtag
にアサインする
Riotタグ要素のコンテキストでは、 this
は tag instanceに紐付きます。
そのため、他のコンテキストで利用する場合にはthis
をtag
として使えるようにしましょう。
Why?
-
this
をtag
という変数に代入することで、他の開発者たちに 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のときにtype
をnone
にセットすることで解除できます。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 を使ってください。
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>