vue-cli(v3) + Nuxt.js + ElementUIを触ってみた

Nuxt.jsが実際のプロダクトで導入されるケースが増えて来ている為、ElementUIと合わせて触ってみました。また、`vue-cli`の`v3beta`が試せるタイミングでしたので、合わせて触ってみました。

# TL;DR

- Nuxt.js + ElementUIのサンプル作成
- `vue-cli`の`v3(現時点では3.0.0-beta.6)`での`vue init`
- `vue add`での`element-ui`ライブラリ導入
- Github：https://github.com/locol23/learn-nuxt-elementui
- 後述のnowでデプロイしたデモサイト：https://learn-nuxt-elementui-gacofatvgh.now.sh
  - コンテナ停止中の場合は、ページが表示されない為、リロードをお願いします。

# 対象読者

- Nuxt.jsが気になっているが、まだ触っていない
- ElementUIをNuxt.jsのプラグインとして導入したい

# Nuxt.jsとは
![Screen_2018_03_27_1_09.png](https://qiita-image-store.s3.amazonaws.com/0/136408/2ae89f47-09d3-dc76-d54c-96084978870f.png)

- Vue.js製のフレームワーク
- ルーティングやSSRが容易に可能
- Vuex（状態管理）についても導入が容易

# ElementUIとは
![Sullscreen_2018_03_27_1_19.png](https://qiita-image-store.s3.amazonaws.com/0/136408/ccd146e3-8f4e-b9f3-7c92-1db6d3760165.png)

- Vue.js用の便利なコンポーネントライブラリ
- 基本的なコンポーネントが揃っている
- React.jsでいうところの[Material-UI](http://www.material-ui.com/)等

# 前提条件
準備として、以下をインストール

- [Node.js](https://nodejs.org/)
- [Yarn](https://yarnpkg.com/en/docs/install)
  - `brew install yarn`

# vue-cliのインストール
`vue-cli`の`v3beta`をグローバルでインストール
※グローバルでインストールしたくない場合はコマンドに`global`を入れずに実行

```
$ yarn global add @vue/cli
```

# `Nuxt.js`のテンプレートプロジェクトを作成

プロジェクト作成の為に`vue init`を実行すると、以下のようなエラーが発生します。

```
$ vue init nuxt-community/starter-template learn-nuxt-elementui

  Command vue init requires a global addon to be installed.
  Please run yarn global add @vue/cli-init and try again.
```

これは、`v3`からは`vue-cli`に`vue init`コマンドが含まれない為、別途インストールする必要があるからです。
参考：[vue-cliのv3からのコマンド一覧](https://github.com/vuejs/vue-cli/blob/dev/docs/cli.md)

## `vue init`コマンドの為に`@vue/cli-init`をインストール

```
$ yarn global add @vue/cli-init
```

`@vue/cli-init`をインストール後、プロジェクト作成を行います。
※設定を特に変更する必要がなければ、`Enter`を3回押下

```
$ vue init nuxt-community/starter-template learn-nuxt-elementui
? Project name learn-nuxt-elementui
? Project description Nuxt.js project
? Author locol23 <xxxxxxxx@yyyyyyy.com>

   vue-cli · Generated "learn-nuxt-elementui".

   To get started:

     cd learn-nuxt-elementui
     npm install # Or yarn
     npm run dev
```

# Nuxtテンプレートサイトの起動確認
以下のコマンドを順に実行

```
$ cd learn-nuxt-elementui
$ yarn 
$ yarn dev
```

最後に`OPEN  http://localhost:3000`が表示されるのを確認し、
ブラウザから[localhost:3000](http://localhost:3000/)へアクセス
下記のページが表示される

![Screen_2018_03_26_22_38.png](https://qiita-image-store.s3.amazonaws.com/0/136408/7a444dc2-eb33-fa7b-ab77-c598640e448e.png)

# ElementUIの導入

## プラグインとして導入
~~本来であれば、`vue-cli`の`v3`からの新コマンド`vue add`にて`Plugin`を導入出来るが、`element-ui`がまだ未対応？の為、以下のように導入
※`vue add element-ui`実行時にパッケージのリポジトリが見つからないエラー発生。申し訳ありませんが、何かご存知の方がいらっしゃいましたら、コメント頂ければ嬉しいです。`vue add apollo`はv3用のリポジトリがある為か、`vue add`可能でした。~~

2018/05/14更新
コメントを頂いて確認したところ、element-uiのvue-cli対応が完了していた為、`vue add element-ui`が可能となっていました。
`yarn add element-ui`の代わりに`vue add element-ui`を実行して下さい。
※ 途中の質問は設定を特に変更する必要がなければ、`Enter`を2回押下
※ 事前に`git init`をしていないと途中でエラーになる為、事前に実行

```bash
$ git init
$ vue add element-ui
// 途中省略
? Use scss theme? Yes
? ElementUi i18n options None
```

```
$ yarn add element-ui // 上記でvue add element-uiをしている場合は実行不要
$ touch plugins/element-ui.js
```

plugins/element-ui.jsを編集

```plugins/element-ui.js
import Vue from 'vue'
import ElementUI from 'element-ui'

const locale = require('element-ui/lib/locale/lang/ja')
Vue.use(ElementUI, { locale })
```
nuxt.config.jsを編集

```nuxt.config.js
   build: {
     /*
     ** Run ESLint on save
     */
     extend (config, { isDev, isClient }) {
       if (isDev && isClient) {
         config.module.rules.push({
           enforce: 'pre',
           test: /\.(js|vue)$/,
           loader: 'eslint-loader',
           exclude: /(node_modules)/
         })
       }
-    }
-  }
+    },
+    vendor: ['element-ui'],
+  },
+  plugins: [
+    '~plugins/element-ui'
+  ],
+  css: [
+    'element-ui/lib/theme-chalk/index.css'
+  ] 
 }
```

# ElementUIを実際に使用
## pages/index.vueの修正
サンプルとして、タブやボタン、アイコン、ラジオコンポーネントを配置

```pages/index.vue
<template>
  <section class="container">
    <el-tabs v-model="activeName" @tab-click="handleClick">
      <el-tab-pane label="User" name="first">User</el-tab-pane>
      <el-tab-pane label="Config" name="second">Config</el-tab-pane>
      <el-tab-pane label="Role" name="third">Role</el-tab-pane>
      <el-tab-pane label="Task" name="fourth">Task</el-tab-pane>
    </el-tabs>

    <div>
      <el-button type="primary">Primary</el-button>
    </div>
    <div>
      <i class="el-icon-edit"></i>
    </div>
    <div>
        <i class="el-icon-loading"></i>
    </div>
    <div>
      <el-radio v-model="radio" label="1">Option A</el-radio>
      <el-radio v-model="radio" label="2">Option B</el-radio>
    </div>
  </section>
</template>

<script>
  export default {
    data() {
      return {
        radio: 1,
        activeName: 'first'
      };
    },
    methods: {
      handleClick(tab, event) {
        console.log(tab, event);
      }
    }
  };
</script>

<style>
.container {
  min-height: 100vh;
  display: flex;
  justify-content: space-around;
  align-items: center;
  flex-direction: column;
  text-align: center;
}
</style>
```
# 最終的なページ
![Screen_2018_03_27_3_21.png](https://qiita-image-store.s3.amazonaws.com/0/136408/398f724d-403f-5f03-300e-aba4179498b9.png)

# まとめ
- Nuxt.jsとElementUIを組み合わせることで、容易にサイト構築が可能
- `nuxt.config.js`に`mode: spa`を追記することで、SPAにすることも可能
- 状況に応じて、[Vuex](https://ja.nuxtjs.org/guide/vuex-store/)を導入し、状態管理可能
- Nuxt.jsは[heroku](https://ja.nuxtjs.org/faq/heroku-deployment/)や[now](https://ja.nuxtjs.org/faq/now-deployment)で容易にサイト公開可能
  - `now`の場合：`learn-nuxt-element`ディレクトリにて`$ yarn global add now`->`$ now`
  - ※初回はメールアドレスが必要

# 参考
- [vuejs/vue-cli](https://github.com/vuejs/vue-cli/blob/dev/docs/cli.md)
- [Nuxt.js](https://ja.nuxtjs.org/)
- [Nuxt.jsとFirebaseを組み合わせて爆速でWebアプリケーションを構築する](https://qiita.com/potato4d/items/cfddeb8732fec63cb29c)
- [VuejsのコンポーネントライブラリElementUIを使ってみた](https://qiita.com/naoki0531/items/0fe96c21cdb62751d6c6)
- [Nuxt.jsとElementを組み合わせて使う](https://qiita.com/teriyakisan/items/9c2f479c30b8a829eb7c)
- [vue-cli-element-ui](https://github.com/cristijora/vue-cli-element-ui)
- [Now でクラウドの複雑さから解放されよう、今すぐに](https://qiita.com/aggre/items/f0cb9f8b8e8c54768e50)