Vue+Webpack+Sassを使ったWebアプリケーションの作り方

# 話す内容
1. vue-routerでのルーティング
1. APIとの通信
1.  vue-routerでのmiddleware周り

---

# 実行環境を作る

Webpackを落としてきます。

```
npm install -g vue-cli
vue init webpack sample
cd sample;npm install
```

Sassなどを入れます。

```
npm install --save node-sass sass-loader axios
```

実行します。

```
npm run dev
```

---

# Sassを使ってみる

1. `HelloWorld.vue` を開きます。
1. `template` と `style` を下記のように修正します。

```
<template>
  <div class="hello">

    .....

    <div class="hello__footer">
      footer
    </div>
  </div>
</template>

<style scoped lang="scss">

.....

.hello {
  &__footer{
    color: #00f
  }
}
</style>

```

`style` で、`lang="scss"` と指定すると、Sassが使えます。

---

# フォルダ構造

下記のようになっています。
基本的に使うのは、 `src/` ディレクトリ配下です。
完全に共通して使うものは、 `index.html` に書きましょう。

```
tree -L 2
.
├── README.md
├── build
│   ├── build.js
│   ├── check-versions.js
│   ├── dev-client.js
│   ├── dev-server.js
│   ├── utils.js
│   ├── vue-loader.conf.js
│   ├── webpack.base.conf.js
│   ├── webpack.dev.conf.js
│   ├── webpack.prod.conf.js
│   └── webpack.test.conf.js
├── config
│   ├── dev.env.js
│   ├── index.js
│   ├── prod.env.js
│   └── test.env.js
├── index.html
├── node_modules
├── package-lock.json
├── package.json
├── src
│   ├── App.vue
│   ├── assets
│   ├── components
│   ├── main.js
│   └── router
├── static
└── test
    ├── e2e
    └── unit
```

---

# Bootstrapの追加といらないものの削除

`index.html` に下記のように修正。

```
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>sample</title>
  </head>
  <body>
    <div id="app"></div>
    <!-- built files will be auto injected -->

    <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js"></script>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
  </body>
</html>
```

`app.vue` を下記のように修正

```
<template>
  <div id="app">
    <router-view/>
  </div>
</template>

<script>
export default {
  name: 'app'
}
</script>

<style>
#app {}
</style>
```

---

# ルーティング
`router/index.js` でルーティングできます。
そのまえに、`src/pages`、 `src/pages/Home` ディレクトリを作成し、 `Home.vue, home.html, home.scss` ファイルを追加しましょう。
そして、 下記のように実装します。

``` lang:Home.vue
<template src="./home.html"></template>
<style lang="scss" src="./home.scss"></style>
<script>
  export default {}
</script>
```

``` lang:home.html
<div class="home">
	<div class="container">
		home
	</div>
</div>
```

---

そして、 `index.html` を下記のように修正します。

```
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
import Home from '@/pages/Home/Home'

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      name: 'Hello',
      component: HelloWorld
    },
    {
      path: '/home',
      name: 'Home',
      component: Home
    }
  ]
})
```

これで、 `/home` のURIをルーティングできました。

---

# APIと通信する
今回は `axios` を使ってリクエストを投げます。
エンドポイントは、configディレクトリ配下のファイルを修正すると良いでしょう。
productionとdevelop環境ごとに設定できます。
下記のように、リクエストを投げたいエンドポイントを書きましょう。

``` lang:dev.env.js
'use strict'
const merge = require('webpack-merge')
const prodEnv = require('./prod.env')

module.exports = merge(prodEnv, {
  NODE_ENV: '"development"',
  HOME_ENDPOINT: '"http://localhost:9999/home"'
})
```

``` lang:prod.env.js
'use strict'
module.exports = {
  NODE_ENV: '"production"',
  HOME_ENDPOINT: '"http://8.8.4.4/home"'
}
```

configファイルをいじった後は、`dev-server`をリスタートしましょう。
再度、 `npm run dev` をしてください。　

---

次に、エンドポイントを `axios` を使って叩きます。
下記のように書くことで、エンドポイントからデータを取ってこれます。

```
<template src="./home.html"></template>
<style lang="scss" src="./home.scss"></style>
<script>
  import axios from 'axios';
  let homeEndpoint = process.env.HOME_ENDPOINT

  export default {
  	created: function() {
  		axios.get(homeEndpoint).then( response => {
  			console.log(response)
  		})
  	}
  }
</script>
```

---

ボタンのクリックでイベントを発火させたい場合は、下記のように実装することでできます。

``` lang:home.html
<div class="home">
	<div class="container">
		home
		<p @click="postData('id')">button</p>
	</div>
</div>
```


``` lang:Home.vue
<template src="./home.html"></template>
<style lang="scss" src="./home.scss"></style>
<script>
  import axios from 'axios';
  let homeEndpoint = process.env.HOME_ENDPOINT
  let postEndpoint = process.env.POST_ENDPOINT

  export default {
  	created: function() {
  		axios.get(homeEndpoint).then( response => {
  			console.log(response)
  		})
  	},
  	methods: {
  		postData: function(id) {
  			axios.post(postEndpoint, {
            	sendData: id
          	})
  		}
  	}
  }
</script>
```

---

# ミドルウェア
`beforeEach()` でフィルターできます。
上記に書いた手順で適当にログイン画面を作り、cookieを発行するようにしてください。

下記のように修正 `index.js`を実装することによって、フィルターの機能ができます。

```lang:router/index.js
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
import Home from '@/pages/Home/Home'
import Login from '@/pages/Login/Login'
import VueCookies from 'vue-cookies'

Vue.use(Router)

let router = new Router({
  routes: [
    {
      path: '/',
      name: 'Hello',
      component: HelloWorld
    },
    {
      path: '/home',
      name: 'Home',
      component: Home
    },
    {
      path: '/login',
      name: 'Login',
      component: Login
    }
  ]
})

router.beforeEach( (to, from, next) => {
  switch (to.path) {
    case '/home':
      if( VueCookies.get('uid') == 'sampleUid' ) {
        next()
      } else {
        next('/login')
      }
      break;
    default:
      next()
      break
  }
})


export default router
```

---

また、ログインが成功した後にリダイレクトしたい場合は、`this.$router.push('/home')` のように記述することでリダイレクトできます。

```
  import VueCookies from 'vue-cookies'

  export default {
  	methods: {
  		login: function() {
  			VueCookies.set('uid', 'sampleUid', '1y')
  			this.$router.push('/home')
  		}
  	}
  }
```

---

# まとめ
- vuejs-templatesのwebpackめっちゃ便利
- ガード周りもう少し綺麗に書けたら最高