新卒でもモダンなフロント開発がしたい！

この記事は[第2のドワンゴ Advent Calendar 2015](http://qiita.com/advent-calendar/2015/dwango2)の18日目です。

# はじめに

こんにちは、2015年新卒入社の[@nagisio](http://qiita.com/nagisio)です。
普段はフロントエンドで開発を行っています。

この記事はjQueryしか書いたことが無かった筆者が、仮想DOMという世界に辿り着くまでの過程を淡々と書いたものです。
過度な期待はしないでください。

_また、本記事の内容は私と同じ初心者の方向けとなっています。_

# フロント開発ってなんなの

まずフロント開発が一体全体何を書くのか抑えておきましょう。
私が普段書いているものは以下です。

* HTML
* CSS
* JavaScript

入社前に私が書いていた（≠書けた）ものも見てみましょう。

* HTML
* CSS
* JavaScript

変わりませんね。
ですが、この大きな枠組みの中に、沢山の技術が含まれているのです。

具体的に述べましょう。 

* HTML
	* Slim
	* Jade
	* ECT
* CSS
	* Sass(SCSS)
	* Less
	* Stylus
* JavaScript
	* Gulp/Grunt
	* AltJS/ES6
	* React.js/Riot.js/Mithril.js
	* Mocha/Jasmine

ほんの一部を挙げました。
9割以上知っている方はこの記事はいささか冗長かもしれません。
私は入社時に恐らくSassぐらいしか知らなかった気がします。

本記事ではこの中から

* Jade
* Sass(SCSS)
* Riot.js

を取り上げ、一つの簡単なプロダクト（ToDo的なやつ）を作ってみます。
また、成果物については、下記のgitリポジトリをご覧いただければと思います。

[nagisio/riot-todo-test](https://github.com/nagisio/riot-todo-test)
http://nagisio.github.io/riot-todo-test/

# 1. HTMLを書く

まずはHTML（の雛形）を書いてみましょう。

```html:index.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8">
    <title>ToDo</title>
    <link rel="stylesheet" href="./styles/app.css">
  </head>
  <body>
    <section id="todo">
      <form>
        <input type="text" name="title">
        <input type="text" name="description">
        <input type="submit" value="Add">
      </form>
    </section>
    <script src="./scripts/app.js"></script>
  </body>
</html>
```

簡単ですね。

今回のようなシングルページで完結する場合、ベタにHTMLを書くので良いかもしれません。
ですが、複数ページを作る場合はどうでしょう。
毎回 `<head>` 内を書くのって面倒じゃないですか？
コピペをすれば簡単？
では `<meta>` タグが一つ増えたら？
CSSの読み込みファイルが増えたら？
etcetc...

**めんどくさくないですか？**

## モダンの波に乗りたい！

上の例では `<head>` と `<body>` の部分を分けることができれば、幸せになれそうです。
そこでいよいよテンプレートエンジン（Jade）の出番です。
詳しい説明は省きます（後述の素晴らしい参考記事やページを見てください）ので、まずはコードを見てください。

```jade:_layout_.jade
doctype html
html(lang='ja')
head
  meta(charset='utf8')
  title ToDo
  link(rel='stylesheet' href='styles/app.css')
body
  block bodyElements
```

`block` という見慣れないキーワードがありますが、その他はHTMLのタグ名そのものです。
Jadeではタグの括弧を書かずにインデントで表現します。

さてこのコード、 `body` タグ内には一見何も書かれていません。

```jade
body // bodyタグ
  block bodyElements // 謎のキーワード
```

Jadeではこの `block` というキーワードを用いて、継承関係を作ることができます。
`bodyElements` という名前のブロックを作っておいて、継承先に実装を任せているのですね。

それでは新しいjadeファイル(index.jade)を用意して、実際に `bodyElements` の中身を書きましょう。
継承には `extends` というキーワードを使用します。

```jade:index.jade
extends _layout_   // _layout_.jadeを継承
block bodyElements // block bodyElementsの中身
  section#todo     // #todoはid="todo"のエイリアス
    form
      input(type='text' name='title')
      input(type='text' name='description')
      input(type='submit' value='Add')
  script(src='./scripts/app.js')
```

これがいわゆる **コンポーネント化** という考え方です。
新しいページを作るときは `_layout_.jade` を継承すれば、 `<head>` の中身は気にしなくて良いのです。

この2つのJadeファイルで出来上がったHTMLは、もちろん始めに書いたHTMLファイルそのものです。

## 参考

* Jade  
http://jade-lang.com/
* Jade について。  
https://gist.github.com/japboy/5402844
* Node.js - Jadeの記法について（あまりまとまっていない）  
http://qiita.com/sasaplus1/items/189560f80cf337d40fdf

# 2. CSSを書く

HTMLがコンポーネント化できたところで、次はCSSを書いていきましょう。
まずは先ほど書いたHTMLをブラウザで見てみます。

<img width="616" alt="" src="https://qiita-image-store.s3.amazonaws.com/0/13956/896020f3-9ee6-e3a5-2e5e-9ffb0e42f874.png">

タイトルと説明を入力するテキストボックスと、追加するボタンがあるだけですね。
何だか味気ないので、CSSを使って装飾しましょう。
まずはCSSを書きやすいように、 `index.jade` の各タグにクラス名を付けておきます。

```jade:index.jade
extends layouts/_layout_
block body
  section#todo
    form#form-todo
      p.headline Title
      input(class='form-title'  type='text'   name='title')
      input(class='form-desc'   type='text'   name='description' placeholder='Description')
      input(class='form-submit' type='submit' value='ToDo')
  script(src='./scripts/app.js')
```

※注
クラスの命名規則に関しては、今回特に考慮していません。
普段は[BEM](https://en.bem.info/)と呼ばれる命名手法に則って書いていますので、興味のある方はそちらもご参照ください。

* BEMを参考にしたCSS設計  
http://qiita.com/mrd-takahashi/items/07dc3b4bad027daa2884
* BEMという命名規則とSass 3.3の新しい記法  
http://blog.ruedap.com/2013/10/29/block-element-modifier

少し長いですが、以下のように書きました。

```css:app.css
section#todo {
  font-family: sans-serif;
  padding: 10px; 
}

p.headline {
  color: #40C4FF;
  margin: 0;
}

input[type='text'] {
  display: block;
  outline: none;
  border-top: none;
  border-right: none;
  border-left: none;
  border-bottom: 1px solid #EEEEEE;
  padding-bottom: 5px;
  transition: all .3s ease;
  width: 240px;
  color: #424242;
}

input[type='text']:focus {
  border-bottom: 1px solid #40C4FF;
}

.form-title {
  font-size: 2rem;
}

.form-desc {
  margin-top: 2rem;
  font-size: 1rem;
}

.form-submit {
  margin-top: 1rem;
  font-size: 1rem;
  padding: .5rem;
  border: none;
  outline: none;
  color: #424242;
  background-color: #EEEEEE;
  cursor: pointer;
}
```

もう一度ブラウザで見てみましょう。

<img width="619" src="https://qiita-image-store.s3.amazonaws.com/0/13956/de8cb944-0f92-2866-b9e0-f7c778c80b06.png">

いい感じになりましたね。
ただし上記のCSSは**危険な**CSSです。

```css:style.css
.form-title {
  font-size: 2rem;
}
```

例えば上記のスタイルは全ての `form-title` クラスについて適用されてしまいます。
つまり後で違うフォームを作成し、 `form-title` クラスを付けてしまうと、上記のスタイルが適用されてしまいます（CSSあるあるですね）。

ではスコープを適切に設定すれば良いでしょうか？

```css:app.css
section#form form .form-title {
  font-size: 2rem;
}
```

これで問題なさそうです。
さてそれでは他のクラスについてもスコープを…

**やっぱりめんどくさくないですか？**

## モダンの波に乗りたい！！

ここではAltCSS（CSSのメタ言語）の一つであるSassを使ってコーディングしてみます。
なお、SassにはSass記法とScss記法と呼ばれる2つの記述方法がありますが、Scss記法の方がもとのCSSの書き方に似ているので、そちらの方が書きやすいと思います。
それではさっそくコードを見てみましょう。

```scss:app.scss
$text-color:   #424242;
$accent-color: #40C4FF;
$dividers:     #EEEEEE;

section#todo {

  font-family: sans-serif;
  padding: 10px;

  p.headline {
    color: $accent-color;
    margin: 0;
  }

  input[type='text'] {
    display: block;
    outline: none;
    border-top: none;
    border-right: none;
    border-left: none;
    border-bottom: 1px solid $dividers;
    padding-bottom: 5px;
    transition: all .3s ease;
    width: 240px;
    color: $text-color;

    &:focus {
      border-bottom: 1px solid $accent-color;
    }
  }

  form {
    .form-title {
      font-size: 2rem;
    }

    .form-desc {
      margin-top: 2rem;
      font-size: 1rem;
    }

    .form-submit {
      margin-top: 1rem;
      font-size: 1rem;
      padding: .5rem;
      border: none;
      outline: none;
      color: $text-color;
      background-color: $dividers;
      cursor: pointer;
    }
  }
}
```

クラスのスタイル定義が入れ子構造になっているのが分かりますね。
そう、Sassでは入れ子構造＝スコープに対応しているのです。
つまり上記の `.form-title` は、CSSに変換すると以下のように展開されます。

```css:app.css
section#form form .form-title {
  font-size: 2rem;
}
```

また、 `app.scss` の初めの数行を見てください。

```scss:app.scss
$text-color:   #424242;
$accent-color: #40C4FF;
$dividers:     #EEEEEE;
```

これはいわゆる変数定義です。色を変更したい時は、この行を変更するだけで一括して変えることができるわけですね。

なお、今回はミニマムなページのため、一つの `.scss` ファイルしか作りませんでした。Sassにももちろんコンポーネント化するための便利な機能が備わっていますので、複数ページを作ったり、ページの情報量が多い場合は、CSSも積極的にコンポーネント化していきましょう。

## 参考

* Sass  
http://sass-lang.com/
* CSSコーディングで泣かないためのSassの基礎知識と10の利点  
http://www.atmarkit.co.jp/ait/articles/1402/17/news102.html

# 3. JavaScriptを書く

それではいよいよJavaScriptを書いていきましょう。
まずは先ほど書いた `index.jade` ファイルに、ToDoリストを追加するための `section` タグを用意しておきます。

```jade:index.jade
extends layouts/_layout_
block body
  section#todo
    form#form-todo
      p.headline Title
      input(class='form-title'  type='text'   name='title')
      input(class='form-desc'   type='text'   name='description' placeholder='Description')
      input(class='form-submit' type='submit' value='ToDo')
  section#list
    // このタグ内にToDoの項目(liタグ)が追加されていく
  script(src='./scripts/app.js')
```

フォームの `submit` ボタンを押すと、この `section#list` タグの中にToDoの項目が追加されるイメージです。
では、どうやって項目を追加すれば良いでしょうか？
もちろん `appendChild()` といったメソッドを用いて追加することは可能です。
 `jQuery` を使用して、DOM要素を指定して、追加するDOMを用意して、 `append()` を呼び出して…

**めんどくさいですよね！**

## モダンの波に乗りたい！！！

ついに仮想DOMの出番です。
上記で色々とモダンな（一部モダンではない気もする）波に乗ってきましたが、この仮想DOMは間違いなくモダンな奴です（一年後はどうなっているか分かりません）。

*乗るしかない、このビッグウェーブに。*

仮想DOMを扱うjsフレームワークはいくつかあり、[React](https://facebook.github.io/react/)が有名です。しかしながら、Reactは学習コストが少し高めということもあり、今回は学習コストが低めな[Riot.js](http://riotjs.com/)を使ってみます。
というのもこのRiot.js、仮想DOMをJadeで書けるのです（！）。

では早速書いてみます。ビッグウェーブに乗りたいのでjsもES6で書きましょう。

※注 ES6については下記の素晴らしい記事をご覧ください…！:pray:

* ES6時代のJavaScript  
http://techlife.cookpad.com/entry/2015/02/02/094607

```js:app.js
'use strict';

import Riot from 'riot'
import Todo from './components/todo.jade'

Riot.mount('section#list', Todo);
```

`app.js` がやっていることはただひとつ、Todoというコンポーネント（＝仮想DOM）を `section#list` タグ内に追加しているだけです。

Todoコンポーネントを見てみましょう。
TodoコンポーネントはJadeファイルですが、htmlのほかにjs（es6）のコードも含まれています。

```js:components/todo.jade
todo
  ul
    li(each='{ todoList }')
      div.title { title }
      div.description { description }

  script.
    const self = this
    self.todoList = []

    self.on('mount', () => {
      document.getElementById('todo-form')
              .addEventListener('submit', onSubmit, false)
    })

    onSubmit = (e) => {
      e.preventDefault()

      let children    = e.target.children
      let title       = children.title
      let description = children.description

      let todo = {
        title: title.value,
        description: description.value
      }

      self.todoList.push(todo)
      self.update(self.todoList)

      title.value = ''
      description.value = ''
    }
```

大事なのは

```
li(each='{ todoList }')
```

と

```
self.todoList.push(todo)
self.update(self.todoList)
```

です。
このコンポーネントはフォームイベントを受け取り、それぞれの内容（titleとdescription）をオブジェクトとして `self.todoList` に追加（push）します。
その後 `self.update(self.todoList)` によって、 `self.todoList` の内容が変化したことを知らせます。
すると `li(each='{ todoList }')` が評価され、`self.todoList` の配列の長さ分だけ `li` タグが生み出されるのです（それも自動で）！

それでは最終的な成果物を見てみましょう。

http://nagisio.github.io/riot-todo-test/

<img width="690" alt="" src="https://qiita-image-store.s3.amazonaws.com/0/13956/c7f87161-c925-304b-1e9c-92eacd1a3835.png">


自動的にTodoが追加されることが確認できました！

## 参考

* Riot.js  
http://riotjs.com/
* Riot.js 2.0 を触ってみた — まだReactで消耗しているの?  
http://qiita.com/cognitom/items/fb1295f3f93911e9e92d
* VirtualDom - なぜ仮想DOMという概念が俺達の魂を震えさせるのか  
http://qiita.com/mizchi/items/4d25bc26def1719d52e6

# おわりに

本記事ではJade/Sass/Riot.jsによる、仮想DOMを用いたモダンなフロント開発について、簡単な例を示しながら紹介しました。
フロントエンドの世界は本記事で紹介しきれない、新しくてわくわくするような技術がまだまだたくさんあります。
まずは小さな世界を覗いて、触れてみて、フロント開発の楽しさを知ってもらえれば幸いです。

私も一フロントエンドエンジニアとして、ますます精進していく所存です。