はじめに
以下の記事の スタイルガイド編 です。
Riot.js と RiotControl で Flux を実装してみる - Qiita
De Voorhoede 社チームのための Riot.js スタイルガイドに載っとり開発しました。スタイルガイドに載っとることでソースコードの一貫性や品質を保つことが出来たかなと思います。
実際に作成したプロジェクト ( 開発環境 ) は以下にリポジトリを置いています。
kotarella1110/riot-starter at v2.0.0
スタイルガイドに載っとる
今回は 開発環境構築編 で作成したプロジェクトに修正を加えてスタイルガイドを反映させていきたいと思います。既にスタイルガイドが反映されている箇所もありますので、そこに関しての説明は省きます。
1モジュール = 1ディレクトリ
1モジュール = 1ディレクトリにするために以下の構成から
.
├── .gitkeep
├── index.html
├── index.js
├── todo.scss
└── todo.tag
以下の構成へ修正します。
.
├── index.html
├── index.js
└── todo
├── todo.scss
└── todo.tag
src/index.js を以下のように修正します。
-import './todo.tag';
+import './todo/todo.tag';
*.tag.html を使う
src/todo/todo.tag から src/todo/todo.tag.html のように変更し、タグの拡張子を修正します。
以下のように *.tag.html ファイルを babel-loader
と riot-tag-loader
が読み込めるように Webpack を修正します。
module: {
rules: [
{ // js
- test: /\.(js|tag)$/,
+ test: /\.(js|tag|tag.html)$/,
include: /src/,
exclude: /node_modules/,
enforce: 'post',
module: {
rules: [
{ // riot
- test: /\.tag$/,
+ test: /\.(tag|tag.html)$/,
include: /src/,
exclude: /node_modules/,
enforce: 'pre',
src/todo/todo.tag.html を import './todo/todo.tag'
とすれば import できるように修正します。
]
},
resolve: {
- extensions: ['.js'],
+ extensions: ['.js', '.html'],
},
plugins: [
new webpack.ProvidePlugin({
タグオプションを設定する
<todo>
- <h3>{ opts.title }</h3>
+ <h3>{ title }</h3>
<ul>
<li each={ items.filter(whatShow) }>
...
<!-- this script this is optional -->
<script>
- this.items = opts.items;
+ this.title = opts.title || '';
+ this.items = opts.items || [];
+ this.text = '';
this.edit = (e) => {
this.text = e.target.value;
thisをtagにアサインする
<!-- this script this is optional -->
<script>
- this.title = opts.title || '';
- this.items = opts.items || [];
- this.text = '';
+ const tag = this;
- this.edit = (e) => {
- this.text = e.target.value;
+ tag.title = opts.title || '';
+ tag.items = opts.items || [];
+ tag.text = '';
+
+ tag.edit = (e) => {
+ tag.text = e.target.value;
};
- this.add = (e) => {
- if (this.text) {
- this.items.push({ title: this.text })
- this.text = this.refs.input.value = '';
+ tag.add = (e) => {
+ if (tag.text) {
+ tag.items.push({ title: tag.text })
+ tag.text = tag.refs.input.value = '';
}
e.preventDefault();
};
- this.removeAllDone = (e) => {
- this.items = this.items.filter((item) => {
+ tag.removeAllDone = (e) => {
+ tag.items = tag.items.filter((item) => {
return !item.done;
});
};
// an two example how to filter items on the list
- this.whatShow = (item) => {
+ tag.whatShow = (item) => {
return !item.hidden;
};
- this.onlyDone = (item) => {
+ tag.onlyDone = (item) => {
return item.done;
};
- this.toggle = (e) => {
+ tag.toggle = (e) => {
const item = e.item;
item.done = !item.done;
return true;
each ... inシンタックスを使う
<h3>{ title }</h3>
<ul>
- <li each={ items.filter(whatShow) }>
- <label class={ completed: done }>
- <input type="checkbox" checked={ done } onclick={ parent.toggle }> { title }
+ <li each={ item in items.filter(whatShow) }>
+ <label class={ completed: item.done }>
+ <input type="checkbox" checked={ item.done } onclick={ parent.toggle }> { item.title }
</label>
</li>
</ul>
...
};
tag.toggle = (e) => {
- const item = e.item;
+ const item = e.item.item;
item.done = !item.done;
return true;
};
タグ名をスタイルスコープとして使う
以下の src/todo/todo.scss ファイルの body
と todo
を分離します。
body {
font-family: 'myriad pro', sans-serif;
font-size: 20px;
border: 0;
todo {
display: block;
max-width: 400px;
margin: 5% auto;
...
以下のように src/main.scss という新規ファイルを作成し、body
のスタイルを記述します。
body {
font-family: 'myriad pro', sans-serif;
font-size: 20px;
border: 0;
}
src/todo/todo.scss は以下のように修正します。
data-is
属性を使ってカスタムタグを作成しているケースも考えられるため、以下のように指定するのが良いでしょう。
todo, [data-is="todo"] {
...
}
src/main.scss ファイルを src/index.js で import することを忘れないでください。
+import './main.scss';
import './todo/todo.tag';
riot.mount('todo', {
...
自分のタグAPIをドキュメント化する
todo
タグのドキュメントを以下のように作成します。
# Todo
## Functionality
Quickly add a todo to a list, and strike them off when you're done.
## Usage
`<todo>` supports the following custom tag attributes:
| attribute | type | description |
| --- | --- | --- |
| `title` | String | Name of the todo list. |
| `items` | Array _optional_ | List of todo items with `title` ( String ) and `done` state ( Boolean ) and `hidden` state ( Boolean ). E.g. `[{ title:'Alpha' }, { title:'Beta', done:true }, { title:'Omega', hidden:true }]`. |
タグのデモを追加する
本稿で最もためになる部分かなと筆者は思っています。
タグについては Sass と ES6 で記述し Webpack でビルドしているため、De Voorhoede 社のスタイルガイドの内容とは異なる方法でデモを追加し、そのデモをブラウザで確認できるようにする必要がありました。アプリ用の HTML とデモ用の HTML を分けてビルドするようにすることでデモをブラウザで確認できるようできるようにしています。
少し詳しくお話ししますと、以下のような構成から
.
├── demos
│ ├── demo
│ │ ├── demo.scss
│ │ └── demo.tag.html
│ ├── index.html // デモ用の HTML
│ └── index.js // デモ用の HTML から読み込まれる JavaScript
├── todo
│ ├── README.md
│ ├── todo-demos.tag.html // todo タグのデモ用のタグ
│ ├── todo.scss
│ └── todo.tag.html
├── index.html // アプリ用の HTML
├── index.js // アプリ用の HTML から読み込まれる JavaScript
└── main.scss
yarn build
でビルドした際に、以下のように出力されるように Webpack の config を設定しています。
.
├── demos.bundle.js // デモ用の HTML から読み込まれる JavaScript
├── demos.html // デモ用の HTML
├── index.html // アプリ用の HTML
├── main.bundle.js // アプリ用の HTML から読み込まれる JavaScript
├── main.css
├── polyfills.bundle.js
└── vendor.bundle.js
まずは demo
タグを作成します。
demo
タグの <yield/>
を使うことでデモをしたいタグを埋め込めるようにします。
import './demo.scss';
<demo>
<p>{ label }</p>
<yield />
<script>
const tag = this;
tag.label = opts.label || '';
</script>
</demo>
demo, [data-is="demo"] {
p {
display: block;
background: #F3F5F5;
padding: .5em;
clear: both;
margin: .5em 0;
}
}
todo-demos
タグという todo
タグのデモ用のタグを作成します。
demo
タグに todo
タグを埋め込むことでデモを追加することができます。
import '../demos/demo/demo.tag';
import './todo.tag';
<todo-demos>
<h2>todo demos</h2>
<demo label="todo with title and empty list">
<todo title="Groceries" />
</demo>
<demo label="todo with title and initial items">
<todo title="Groceries" items="{ [{ title:'Apples' }, { title:'Oranges', done:true }, { title:'Grapes', hidden:true }] }" />
</demo>
</todo-demos>
src/demos/index.js ファイルを作成します。
先ほど作成した todo-demos
タグを import し、マウントします。
import '../todo/todo-demos.tag';
riot.mount('*');
最後に HTML ファイルを作成します。
<!doctype html>
<html>
<head>
<title>Riot Demos</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!--[if lt IE 9]>
<script src="https://cdnjs.cloudflare.com/ajax/libs/es5-shim/4.0.5/es5-shim.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.2/html5shiv.min.js"></script>
<script>html5.addElements('todo')</script>
<![endif]-->
</head>
<body>
<todo-demos></todo-demos>
</body>
</html>
後は Webpack の config を修正して、 デモ用の HTML として出力するようにするだけです。
まずは、 webpack/paths.js に先ほど作成したデモ用の HTML と JavaScript のパスを追加します。
...
export default {
srcHtml: path.join(__dirname, '../src/index.html'),
+ srcDemosHtml: path.join(__dirname, '../src/demos/index.html'),
srcJs: path.join(__dirname, '../src/index.js'),
+ srcDemosJs: path.join(__dirname, '../src/demos/index.js'),
distDir: path.join(__dirname, '../dist')
}
html-webpack-plugin
を使って HTML の出力を分けるようにしてあげましょう。chunks
ではどの entry
を HTML ファイルに含めるかを定義しています。
デモ用の HTML は開発環境の時だけ出力されるように webpack/dev.config.js
ファイルを修正します。
import webpack from 'webpack';
+import HtmlWebpackPlugin from 'html-webpack-plugin';
import env from '../env.js';
import paths from './paths.js';
...
entry: {
vendor: [
'riot-hot-reload'
+ ],
+ demo: [
+ paths.srcDemosJs
]
},
module: {
...
'NODE_ENV': JSON.stringify('development'),
}
}),
- new webpack.HotModuleReplacementPlugin()
+ new webpack.HotModuleReplacementPlugin(),
+ new HtmlWebpackPlugin({
+ template: paths.srcDemosHtml,
+ filename: 'demos.html',
+ chunks: ['demo', 'polyfills', 'vendor']
+ }),
],
devtool: 'inline-source-map',
devServer: {
アプリ用の HTML も今まで通り出力されように webpack/dev.config.js
ファイルを修正します。
}),
new HtmlWebpackPlugin({
template: paths.srcHtml,
+ chunks: ['main', 'polyfills', 'vendor']
}),
new CleanWebpackPlugin(['*'], {
root: paths.distDir,
これでデモページを表示できるようになりました。
yarn start
を実行すると、ブラウザ上でアプリ用の HTML が表示されると思います。 /demos.html
とパスを追加してあげるとデモ用の HTML が表示できます。
タグファイルをlintする
省略
プロジェクトにバッジをつける
README.md にバッジをつけます。
最後に
筆者が作成したプロジェクトに誤りがある場合はプルリクエストやコメント等でご指摘お願いします。