Phoenix1.4 でのvue環境構築メモ（Part1: 単一ファイルコンポーネントを使えるようにするまで）

(この記事は「[fukuoka.ex Elixir／Phoenix Advent Calendar 2018](https://qiita.com/advent-calendar/2018/fukuokaex)」の4日目です)

こんにちは、@koga1020です。 早いもので、Advent Calendarのシーズンですね。全然冬らしくない暑さの福岡よりお届けしております（笑）

## 本題
以前、[Phoenix + Vue.js入門](https://qiita.com/koga1020/items/c02a0fd5ae11fb5da1e0) を投稿したのですが、こちらの記事ではVue.jsの部分はサクッとCDNから利用する方法で書いていました。

本記事では、Phoenix1.4に標準で入っているWebpack環境を利用してVueの単一ファイルコンポーネント（.vueファイル） のビルド環境を整える手順をまとめたいと思います。

## 環境
- Elixir 1.7.3
- Phoenix 1.4.0

## 前提
- Phoenix1.4の環境が作れている
- 上記環境で、npm or yarn を叩ける状態

まで進めている方を想定しています。

以下に、検証用に作ったdocker-composeを置いておきます。「これから環境作ってみる」という方は使えるかもしれません。

https://github.com/koga1020/phoenix1.4-vue-template

## 手順

### パッケージのインストール
vue, vue-loader, vue-template-compilerを入れます

```bash
cd assets
yarn add vue
yarn add -D vue-loader vue-template-compiler
```

### webpack.config.jsの修正
```javascript
const path = require('path');
const glob = require('glob');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const VueLoaderPlugin = require('vue-loader/lib/plugin'); // 追加

module.exports = (env, options) => ({
  optimization: {
    minimizer: [
      new UglifyJsPlugin({ cache: true, parallel: true, sourceMap: false }),
      new OptimizeCSSAssetsPlugin({})
    ]
  },
  entry: './js/app.js',
  output: {
    filename: 'app.js',
    path: path.resolve(__dirname, '../priv/static/js')
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader'
        }
      },
      // 追加
      {
        test: /\.vue$/,
        use: {
          loader: 'vue-loader'
        }
      },
      {
        test: /\.css$/,
        use: [MiniCssExtractPlugin.loader, 'css-loader']
      }
    ]
  },
  // 追加
  resolve: {
    extensions: ['.js', '.vue', '.json'],
    alias: {
      vue$: 'vue/dist/vue.esm.js',
    }
  },
  plugins: [
    new MiniCssExtractPlugin({ filename: '../css/app.css' }),
    new CopyWebpackPlugin([{ from: 'static/', to: '../' }]), // ← 末尾のカンマをお忘れなく！
    new VueLoaderPlugin() // 追加
  ]
});

```

### js/app.jsの修正
```javascript
// We need to import the CSS so that webpack will load it.
// The MiniCssExtractPlugin is used to separate it out into
// its own CSS file.
import css from "../css/app.css"

// webpack automatically bundles all modules in your
// entry points. Those entry points can be configured
// in "webpack.config.js".
//
// Import dependencies
//
import "phoenix_html"

// Import local files
//
// Local files can be imported directly using relative paths, for example:
// import socket from "./socket"

// 以下を追加
import Vue from 'vue';
import App from './App.vue';

new Vue(App).$mount('#app');
```

### App.vueの作成
js/App.vueを作成後、以下を記述します

```vue
<template>
<div>タイトル: {{ title }}</div>
</template>

<script>
export default {
  name: 'app',
  data () {
    return {
      title: 'This is App.vue!!'
    }
  }
}
</script>
```

### app.html.eexの修正

vueコンポーネントをマウントする、id="app"の要素を追加します。mainタグの中をごそっと変えてみましょう

```html
    <main role="main" class="container">
      <div id="app"></div>
    </main>
```

### ビルド
assetsフォルダ内で、以下を叩きましょう。

```bash
yarn run watch
```
ビルド対象ファイルの変更を検出して自動でビルドが走るようになります。これでApp.vueに書いた内容もビルドされています。

### Phoenixを起動
yarn run watchがフォアグラウンドで動いているので、別シェルでPhoenixを起動してください。

```
mix phx.server
```


### ウェルカム画面を確認
App.vueに書いた内容が表示されました！


![screencapture-localhost-4001-2018-12-02-17_01_47.png](https://qiita-image-store.s3.amazonaws.com/0/99116/514af7eb-5d3c-dd20-537a-13692a2a16af.png)


## まとめ
Phoenix1.4からデフォルトで準備されているwebpackを用いて、vueの単一ファイルコンポーネントを利用できる状態になりました。あとはvue-routerやaxiosあたりを追加していけば良さそうです。



明日の「[fukuoka.ex Elixir／Phoenix Advent Calendar 2018](https://qiita.com/advent-calendar/2018/fukuokaex)」5日目の記事は， @takasehideki さんの「[ElixirでIoT#2.3：ラズパイの温湿度と超音波センサ値をPhoenixでサクッと？リアルタイム表示](https://qiita.com/takasehideki/items/b0a07455d88a1f349a6e)」です。お楽しみに！