vue.jsのcomponentをwebpackで.vueにして単一ファイルコンポーネントにする

vue.jsのcomponentを `.vue` という独立した1つのファイルで管理する方法のまとめです。
vue.js公式のガイドではちらっと出たくらいで、vue-loaderなどのドキュメントを読む必要があります。
Rails5.1beta ではいきなりこの形式のhello worldが入っているので戸惑う方が多かったのではないでしょうか。
僕もその一人です。
コンポーネントと単一ファイルコンポーネントを並べて見比べる形の備忘録的なまとめです。

# 環境
- vue: 2.2.6
- vue-loader: 11.3.4
- vue-style-loader: 2.0.5
- vue-template-compiler: 2.2.6
- webpack: 2.3.3

当方はjsフレームワークはvue.jsが初めてなのでreactなどとの比較は出てこないです。

# componentとは
公式によると

> コンポーネントは Vue.js の最も強力な機能の 1 つです。基本的な HTML 要素を拡張して再利用可能なコードのカプセル化を助けます。高いレベルでは、コンポーネントは Vue.js のコンパイラが指定された振舞いを加えるカスタム要素です。場合によっては、特別な is 属性で拡張されたネイティブな HTML 要素の姿をとることもあります。

[コンポーネント - Vue.js](https://jp.vuejs.org/v2/guide/components.html)

つらつら書かれていますが、要するに「拡張したHTMLを一塊にして独立させたもの」なイメージ。
パーツ（機能）単位で　**HTMLをまとめて** どこで使っても同じように再利用できるようにする強力な機能。
vue.js本体のMVVMと相まってjQueryでは面倒そうなものをすっきり書けてしかも使いまわせる。やばい。 :thumbsup:

# 単一ファイルコンポーネント
基本的には普通のコンポーネントと同じで、パーツ単位でHTMLをまとめられる。
ただし、違うところは、名称の通り、その「パーツを構成するために必要な **HTML・CSS・JSをひとまとめ** に」して独立した1つのファイルで扱える。

# 単一ファイルコンポーネントは何が嬉しいのか
ざっくりこんな感じ。

|     | コンポーネント | 単一ファイルコンポーネント |
| --- | ---------- | ------------------- |
| Vueのグローバル汚染 | あり | なし | 
| シンタックスハイライト | なし | あり |
| CSS | 無視される ※ | 有効 |
| Javascript制限 | あり ※ | なし |

この表だけだと語弊が生まれる（特に※があるもの）ので公式も見てね。
[単一ファイルコンポーネント - Vue.js](https://jp.vuejs.org/v2/guide/single-file-components.html#前書き)

特に個人的に嬉しいところは、さっきのこれ
「パーツを構成するために必要な **HTML・CSS・JSをひとまとめ** に」

これまではHTML・CSS・JSをそれぞれ別のファイルで管理して、id・class、詳細度、グローバル汚染に悩み、悩まされることが多々ありました。
ですが、これがあると、そんな悩みは吹き飛ぶわけですね。 :open_hands:
なぜなら、それら全てがコンポーネントの `.vue` ファイルの中で閉じられるからですね。 :earth_asia: 

# コード比較

単一ファイルコンポーネントをべた褒めしてきましたが、学習するのは面倒です。
見なければならないファイルの数が増えるわけですから。
なので、通常のコンポーネントと比較して単一ファイルコンポーネントを追っていきます。

## コンポーネントを使うときはこう

```javascript:app.js
// 登録する
Vue.component('my-component', {
  template: '<div>A custom component!</div>'
})

// root インスタンスを作成する
new Vue({
  el: '#example'
})
```

`Vue` オブジェクトに対して `my-component` という名前で `template` 部分のHTMLを登録（作成）する。
メインのインスタンスで `vue.js` が対象とするのは `#example` 。

```html
<div id="example">
  <my-component></my-component>
</div>

<script src="./app.js"></script>
```

HTMLは、 root要素に `id="example"` をつける。
その中のコンポーネントを挿入したいところに、呼び出すコンポーネントの名前と同じタグ（のようなもの）を記述する。
そして `app.js` を読み込む。

と、結果は次の通り。

```
<div id="example">
  <div>A custom component!</div>
</div>
```

コンポーネントを `Vue` オブジェクトを拡張する形で登録（作成）し、メインのインスタンスを作るとコンポーネントの名前でHTMLが置換される。


## 単一ファイルコンポーネントを使うときはこう


```html:my-component.vue
<!-- 登録する -->
<template>
  <div>A custom component!</div>
</template>
```

`.vue` ファイルに `<template>` タグを埋め込んでその中にHTMLを書き込む

```javascript:app.js
import MyComponent from './my-component.vue';

// root インスタンスを作成する
new Vue({
  el: '#example',
  components: { MyComponent },
  template: '<my-component></my-component>'
})
```

ここは変わらず、メインのインスタンスで `vue.js` が対象とするのは `#example` 。
違うのは、 `components` で使いたいコンポーネントのオブジェクトを指定して、 `template` でコンポーネントと置き換えるタグ（のようなもの）を指定する。
もちろん、 `my-component.vue` は読み込む必要がありますので、 `import` で読み込みます。

```html
<div id="example">
  <my-component></my-component>
</div>

<script src="./app.js"></script>
```

ここも変わらず、HTMLは、 root要素に `id="example"` をつける。
その中のコンポーネントを挿入したいところに、呼び出すコンポーネントの名前と同じタグ（のようなもの） `<my-component>` を記述する。
そして `app.js` を読み込む。

結果は同じ。
ただし、コンパイルが必要です。

## 単一ファイルコンポーネントを拡張する
先の例だと、HTMLしか出てきませんでしたが、もちろんJSとCSSも記述できます。

```html:my-component.vue
<template>
  <div><p v-if="isVisible">{{ message }}</p></div>
</template>

<script>
export default {
  data: function() {
    return {
      message: 'hello'
    }
  },
  computed: {
    isVisible: function() {
      if (this.message) {
        return true;
      } else {
        return false;
      }
    }
  }
}
</script>

<style lang="scss" scoped>
// langを指定すると、scssやsassでかける。その時は、scss-loaderが必要になる
// scoped をつけると、そのスタイルはこのファイル内にとどまります。
div {
  text-align: center;
  p {
    color: red;
  }
}
</style>
```

## webpack設定
コンパイルが必要になるのでその件。
ローダーとか
Rails 5.1beta の場合は `rails new hogehoge --wabpack=vue` ってやれば揃えてくれる。

# まとめ
また後で