Nuxt.jsの学習（インストールからビルドまで）


# はじめに

Nuxt.js（とVue.js）を使ってサイトを作る、を学習しました。
Nuxt.js初心者が、インストールからビルド、サーバーにアップするまでにしたこととその流れをまとめます。

## 前提

- 作業環境
  - PC：Mac（macOS Sierra）
  - エディタ：Atom
- 前提知識
  - Vue.js -> ほぼ整備済のVue.jsプロジェクトを触った程度
  - Wordpress -> サイトを作る一通りの知識がある
- 今回使用したツールのバージョン
  - Node.js -> `9.3.0`
  - npm -> `5.6.0`
  - Yarn -> `1.3.2`
  - VCCW -> `3`
  - Vue.js -> `2`
  - Nuxt.js -> `1.0.0-rc11`（学習の間にver.[`1.0.0`](https://github.com/nuxt/nuxt.js/releases/tag/v1.0.0)が出ました🎉）
  - aws-cli -> `1.14.22`
  - vue-cli -> `2.9.2`
- 作業前に導入済のツール
  - Node.js
  - npm
  - Yarn
  - VirtualBox
  - Vagrant
  - VCCW（ローカル環境で動くWordpress）
  - aws-cli
  - vue-cli
- 端折ること
  - 👆の導入方法
  - Vue.jsに関する基本的な操作

## Vue.jsとは

ex: https://jp.vuejs.org

> Vue (発音は / v j u ː / 、 view と同様）はユーザーインターフェイスを構築するためのプログレッシブフレームワークです。

ref: [はじめに — Vue.js](https://jp.vuejs.org/v2/guide/#Vue-js-%E3%81%A8%E3%81%AF%EF%BC%9F)

- JSによってDOMが描画される（=バーチャルDOM）
- JSとHTML・CSSのコードは分けて扱われる

## Nuxt.jsとは

ex: https://ja.nuxtjs.org/

> Nuxt.js とはユニバーサルな Vue.js アプリケーションを構築するためのフレームワークです。

ref: [はじめに - Nuxt.js](https://ja.nuxtjs.org/guide#nuxt-js-%E3%81%A8%E3%81%AF%E4%BD%95%E3%81%8B-)

- Vue.jsを含んだ（Vue.jsベースの？）フレームワーク
- Vue.js以外にもルーターや状態管理など制作のうえで必要となる機能を全部盛りした状態
  - Vue.js
  - Vue-Router
  - Vuex
  - Vue Server Renderer（`mode: 'spa'` を利用しているときを除く)
  - Vue-Meta
  - Webpack
  - Babel
  - ESLint


----------


# 1. 準備

Vue.jsとNuxt.js以外に知っておくこと👇

- npm
- Yarn
- EditorConfig (`.editorconfig`)
- ESlint (`.eslintrc`, `.eslintignore`)
- `.babelrc`
- vue-cli

## npm

ex: https://www.npmjs.com/

> [Node Package Manager(npm)](https://www.npmjs.org/)とはNode.jsのライブラリやパッケージを管理することができるツールです。
> 　（中略）
> Node.jsのパッケージマネージャであるnpmは、Node.jsと一緒にインストールされています。 またnpmでインストールできるパッケージが登録されており、[npmjs.org](https://www.npmjs.org/)からどのようなパッケージが管理できるかを確認することができます。

ref: [STEP2-4.パッケージマネージャのnpmとは / チームラボ オンラインスキルアップ課題](https://team-lab.github.io/skillup-nodejs/2/4.html)


- npm = Node Package Manager
- Node.jsのパッケージ管理ツール
- npm5から（`shrinkwrap.json`ではない）依存パッケージを固定する機能がついた  
  ref: [npm v5 がリリースされた - from scratch](http://yosuke-furukawa.hatenablog.com/entry/2017/05/30/090602)

## Yarn

ex: https://yarnpkg.com/ja/

> Yarn はダウンロードしたパッケージをキャッシュするので、再ダウンロードは不要です。さらにリソースを最大限利用できるように処理を並列化するので、インストール時間はかつてないほど高速です。

- Facebook発のパッケージ管理ツール
- パッケージの並列インストールができる（npmはひとつずつインストール）
- パッケージがインストール済みの場合はオフラインで再インストールできる

ref: https://www.webprofessional.jp/yarn-vs-npm/

## EditorConfig

ex: http://editorconfig.org/

- 様々なエディターで利用できる共通の書式設定ファイル
- 文字コード等の書式をそのディレクトリー以下のファイル編集時に固定できる
- 文字コード・改行コード・インデント等を指定できる
- 複数人での作業時に便利

## ESlint

ex: https://eslint.org/

- JavaScriptとJSX向けの構文チェックツール
- Node.js バージョン**4**以上 / npm バージョン**2**以上で使える　

### 設定ファイル

#### .eslintrc.js

- ESLint自体の設定（環境・ルールなど）をここに書く
- プロジェクトルートに置く
- yamlファイル（`.eslintrc.yml`）やjsonファイル（`.eslintrc.json`）としてもOK
- `package.json`に書くこともできる

ref: https://eslint.org/docs/user-guide/configuring

```javascript
// example
module.exports = {
  // .eslintrc.jsが置いてあるディレクトリをルートとするかどうか
  root: true,
  
  // 構文解析にどれを使うか
  parser: 'babel-eslint',
  
  // パーサーのオプション指定
  parserOptions: {
    sourceType: 'module'
  },
  
  // 環境の指定
  env: {
    browser: true,
    node   : true
  },
  
  // 追加で判定するコードがある場合はここで指定
  plugins: [
    'html'
  ],
  
  // グローバル変数がある場合はここに書く
  globals: {
    jQuery  : true
  },
  
  // カスタムルールの追加
  // ref: https://eslint.org/docs/rules/
  'rules': { ... }
}
```


#### .eslintignore

- チェックから除外するディレクトリ・ファイルをここに書く

ref: https://eslint.org/docs/user-guide/configuring#ignoring-files-and-directories

```
# example: .eslintignore

# Nuxtのビルドファイル
.nuxt/*.js

# `nuxt generate`時のディレクトリ
dist/*.js

# npmパッケージ
node_modules/*.js

# プラグインとして使用するファイル
plugins/*.js
```

### vue-cli

- Vue.js（とNuxt.js）をインストールする時は、`vue-cli`を使うと開発するのに必要なファイルを用意してくれる
- `vue-cli`のインストール方法は👇を参照  
  ex: https://github.com/vuejs/vue-cli#installation


# 2. インストール

```bash
# 1. 開発に必要なファイルをインストール
$ vue init nuxt-community/starter-template プロジェクト名

# 2. プロジェクトディレクトリに移動
$ cd プロジェクト名

# 3. 必要なパッケージをインストール
$ yarn install # またはnpm install
```

Nuxt.jsを使う場合は`vue-cli`のデフォルトにはないテンプレート（`nuxt-community/starter-template`）を指定する。
その他にも目的に応じたテンプレートがある👇
ex: https://github.com/nuxt-community/starter-template


# 3. 設定

ref: [設定 - Nuxt.js](https://ja.nuxtjs.org/guide/configuration)（全ての項目は[英語ドキュメント](https://nuxtjs.org/guide/configuration)を参照）

```javascript
// example:
module.exports = {
  // アプリケーションのモード - SSRしない場合に指定する
  // ref: https://nuxtjs.org/api/configuration-mode#the-mode-property
  mode: 'spa',

  // 共通のCSSファイルを読み込む場合はここで指定
  // Tips: ~または@ = ソースディレクトリ
  css: ['~/assets/css/style.scss'],

  // ヘッダ情報
  // ページごとに設定することもできる
  // ref: https://nuxtjs.org/api/pages-head
  head: {
    title: 'nuxt-project',
    meta: [
      { charset: 'utf-8' },
      { name: 'viewport', content: 'width=device-width, initial-scale=1' },
      { hid: 'description', name: 'description', content: 'Nuxt.js project' }
    ],
    link: [
      { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' },
      { rel: 'stylesheet', type: 'text/css', href: 'https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,900' }
    ]
  },

  // [TBD] デフォルトでついてるローディングバーの設定
  loading: false,

  // [TBD] ビルド設定
  build: {
    /*
    ** Run ESLint on save
    */
    extend (config, ctx) {
      if (ctx.dev && ctx.isClient) {
        config.module.rules.push({
          enforce: 'pre',
          test: /\.(js|vue)$/,
          loader: 'eslint-loader',
          exclude: /(node_modules)/
        })
      }
    }
  },

  // 静的ファイルとしてビルド時の書き出し先（この場合は`/dist/app/`以下に書き出される）
  generate: {
    dir: 'dist/app'
  },

  // ルーティングのベースとなるパス
  // ルート以外のURL（下層ページなど）の場合に指定
  router: {
    base: '/app/'
  },

  // ソースファイルのディレクトリ
  // デフォルトからディレクトリ構成を変える場合は指定
  srcDir: 'src/'
}
```

# 4. 動かしてみる

```bash
# devサーバーを起動（`nuxt build` & `nuxt start`）
$ npm run dev
```

- `npm run dev`すると`/.nuxt/`以下にファイルが生成される
- http://localhost:3000/で表示される
- ホットリロードあり


# 5. もっと動かしてみる

- 自分のサイトをNuxt化してみる
  - http://dev.lisverb.com/
  - スタイルはScssで書く
  - テキストなどはローカル環境のWordpressから投稿保存毎にjsonファイルを吐き出すかたち（端折ります）
  - ~~とりあえずトップページのみ~~ → 下層ページを作った
- 下層ページを作る
  - http://dev.lisverb.com/works/

## TODO

1. テンプレート
2. Wordpressと併用する場合
3. SEOまわりの設定
4. [WIP] デプロイする
5. 疑問の解消

## 1. テンプレート

### ビュー

- ビューにあたる部分は`/components` `/layouts` `/pages` となる
  - **このディレクトリ名は変更不可**
  - `components`：`layouts`や`pages`に使用できるコンポーネントファイル
  - `layouts`：`pages`内のVueファイルが表示される（デフォルト以外にも作れる）
  - `pages`：ページごとのVueファイル、ここで作ったディレクトリ通りにルーティングが作られる

#### `/components`ファイルを`/pages`ファイルで読み込む場合

```html
<!-- example: componentsファイル（/components/ExampleComponent.vue） -->

<template>
  <div>
    hogehoge...
  </div>
</template>

<script>
export default {
  // name: ExampleComponent は不要、つけるとエラーになった
}
</script>
```

```html
<!-- example: pagesファイル（読み込み元のファイル） -->

<template>
  <div>
    <ExampleComponent/>
  </div>
</template>

<script>
import ExampleComponent from '~/components/ExampleComponent.vue'
export default {
  components: {
    ExampleComponent
  }
}
</script>
```

### スタイル

- 共通スタイルのみ`/assets/css`以下に追加する
  - 余談：コンポーネントやレイアウトに依存するスタイルはVueファイル内に書くかたちとした

### 処理しないファイル

- ビルド時に何も処理しないファイルは`/static`以下に追加する
  - ex: `favicon.ico`など


## 2. Wordpressと併用する場合

> テキストなどはローカル環境のWordpressから投稿保存毎にjsonファイルを吐き出すかたち

とした際につまづいた。

### ディレクトリ構造

`npm run generate`すると書き出し先ディレクトリのファイルが削除されるので、
VCCWなどでローカル環境にWordpressをインストールする場合は注意が必要。

> NGな例：`npm run generate`時に`/dist`以下のファイルが削除される
> 書き出し先ディレクトリ：`/dist`
> Wordpressディレクトリ：`/dist`


> SAFEな例①：`/dist`以下はプロキシする（※）
> 書き出し先ディレクトリ：`/dist`
> Wordpressディレクトリ：`/wp`


> SAFEな例②：`npm run generate`時に削除されるのは`/dist/app`以下のファイルのみ
> 書き出し先ディレクトリ：`/dist/app`
> Wordpressディレクトリ：`/dist/wp`

#### ※ SAFEな例①でプロキシする方法：

- Nuxtの追加モジュールを使う  
  （[`http-proxy-middleware`](https://github.com/chimurai/http-proxy-middleware)を`nuxt.config.js`で設定できるようにしたもののよう）  
  ex: https://github.com/nuxt-community/modules/tree/master/packages/proxy

```bash
# 1. bash - モジュールを追加
$ yarn add @nuxtjs/proxy # or $ npm install @nuxtjs/proxy

# 2. nuxt.config.js - 設定を追加
module.exports = {
  // モジュール追加
  modules: [
   '@nuxtjs/proxy'
  ],
  // プロキシ設定
  proxy: {
    '/api': 'http://example.com'
  }
}
```

### Wordpress内でのパスの指定

- SAFEな例①の構成で、`/dist`以下のパスを指定したい
- VCCWでWordpressの環境を作った

の場合

```php
<?php
  // 場所：テーマファイル内など
  // '/vagrant/' としても正しく指定できない
  // WPがインストールされた階層から`../`でプロジェクトルートまで戻ってみる（VCCW設定の`document_root`による）
  realpath(ABSPATH . '../../../vagrant/')
?>
```

- `ABSPATH`：WordPressのインストールされたパス名を返す
  ref: https://elearn.jp/wpman/variable/abspath.html
- `realpath()`：相対パスなどを解決して絶対パスに直す
  ref: http://php.net/manual/ja/function.realpath.php


## 3. SEOまわりの設定

### OGタグの追加

- `nuxt.config.js`に追加する  
  ref: https://nuxtjs.org/api/configuration-head#the-head-property
- 使い方は[`vue-meta`](https://github.com/declandewet/vue-meta)と同じ
- 子コンポーネント（下層ページ）のメタ情報を個別に設定する場合は、`hid`の値を揃える

```javascript
// example: nuxt.config.js
module.exports = {
  head: {
    // title: 'site title',
    meta: [
      // { charset: 'utf-8' },
      // { name: 'viewport', content: 'width=device-width, initial-scale=1' },
      // { hid: 'description', name: 'description', content: 'meta description' },
      { name: 'fb:admins', content: 'admin id' },
      { name: 'og:type', content: 'website' },
      { name: 'og:url', content: 'url' },
      { name: 'og:title', content: 'og page title' },
      { name: 'og:site_name', content: 'og site name' },
      { name: 'og:description', content: 'og description' },
      { name: 'og:image', content: 'og image' } // など...
    ],
    // link: [
    //  { rel: 'icon', type: 'image/x-icon', href: '/icon/favicon.ico' }
    // ]
  }
}
```

### GAコードを追加する

2通り方法がありそう…？

#### 1. モジュールを追加する

##### 手順1：モジュールの追加

```bash
$ yarn add @nuxtjs/google-analytics # or $ npm install @nuxtjs/google-analytics
```

##### 手順2：設定の追加
    
```javascript
// nuxt.config.js
module.exports = {
  // モジュールを追加
  modules: [
    '@nuxtjs/google-analytics'
  ],
  // アナリティクス情報を追加
  'google-analytics': {
    id: 'UA-00000-0' // トラッキングID
  }
}
```

ref: https://github.com/nuxt-community/analytics-module


#### 2. `/plugins`にファイルを追加する

手順1：`/plugins`以下にコードを追加

[TBD] 👇の内容を追加する。
ex: https://ja.nuxtjs.org/faq/google-analytics/

##### 手順2：設定の追加

```
// nuxt.config.js
module.exports = {
  plugins: [
    { src: '~plugins/ga.js', ssr: false } // サーバー側で処理しない
  ]
}
```

ref: https://ja.nuxtjs.org/faq/google-analytics/

### Google Search Consoleでの確認

- 🙅トラッキングコードでの確認（コード自体は読み込みされるが`<head>`内に書かれていないため…？）
- 🙅メタタグでの確認（…？）
- 🙆ファイルのアップロードでの確認


## [WIP] 4. デプロイする

### 前提
- AWS S3へ`nuxt generate`したファイルをアップしたい

### `aws-cli`でアップする場合

##### 手順1：Vagrantに`aws-cli`をインストール

※`pip`・`python`がインストールされている必要がある

```bash
# 0. SSHログイン
$ vagrant ssh

# 1. ルート権限になる
$ sudo su -

# 2. `pip`をダウンロード・インストール
root@xxx:~# curl "https://bootstrap.pypa.io/get-pip.py" -o "get-pip.py"
root@xxx:~# python get-pip.py

# 3. `aws-cli`インストール
root@xxx:~# pip install awscli
```

##### 手順2：バケット情報設定

```bash
# vagrant ssh済の状態で
$ aws configure
```

`aws configure`の手順は👇を参照。
ref: https://github.com/aws/aws-cli#getting-started

##### 手順3：アップロード

```bash
# vagrant ssh済の状態で
# S3へ該当ファイル・ディレクトリをアップロード
$ aws s3 sync --delete --exclude "PATH_TO_EXCLUDE_FILE_OR_DIRECTORY" --exact-timestamps --acl public-read PATH_TO_GENERATE_DIRECTORY s3://バケット名/
```

### `nuxt generate`時にデプロイする（やりたいこと）
  [WIP]

### その他

その他にNetlifyでデプロイする方法も試しましたがとても簡単にできました。
ref: https://qiita.com/gupuru/items/e9746df176261afc3af2#netlify

## 5. 疑問の解消

### Sass変数をVueコンポーネントファイルでも使えるようにする

- [`nuxt-sass-resources-loader`](https://github.com/anteriovieira/nuxt-sass-resources-loader)を使う
  - [`sass-resources-loader`](https://github.com/shakacode/sass-resources-loader)のNuxtモジュール
  - 設定内容も[`sass-resources-loader`](https://github.com/shakacode/sass-resources-loader)と同じ
    
```bash
# example: 
# 1. bash - モジュールの追加
$ yarn add nuxt-sass-resources-loader
```

```javascript
// 2. nuxt.config.js - 設定の追加
module.exports = {
  // modules
  modules: [
    'nuxt-sass-resources-loader'
  ],

  // global variable
  // variable.scss = 変数をまとめたファイル
  // プロジェクトルートからの相対パス（Nuxtのソースディレクトリ指定`~`が使えなかった...）
  sassResources: './src/assets/css/variable.scss'
}
```

👆でNuxtでもコンポーネントごとに`variable.scss`をインポートせず変数を使えるようになる。
ref: [vue-loader/pre-processors.md at master · vuejs/vue-loader](https://github.com/vuejs/vue-loader/blob/master/docs/ja/configurations/pre-processors.md#%E3%82%B0%E3%83%AD%E3%83%BC%E3%83%90%E3%83%AB%E8%A8%AD%E5%AE%9A%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AE%E8%AA%AD%E3%81%BF%E8%BE%BC%E3%81%BF)


## 6. ビルド
```bash
# `nuxt build`
# [TBD]
$ npm run build

# `nuxt generate`
# 静的ファイルとして書き出す
$ npm run generate
```

### ビルド先の指定

- `nuxt generate`（`npm run generate`）のビルド先は`nuxt.config.js`で変更できる

```javascript
// example: nuxt.config.js
module.exports = {
  generate: {
    // プロジェクトルートからのパス（この場合は`/htdocs/`以下にビルドされる）
    dir: 'htdocs'
  }
}
```

### ビルド時の疑問

- [TBD] `nuxt build`と`nuxt generate`の違い


## 7. サーバーで

`nuxt generate`（`npm run generate`）でビルドされたファイルをサーバーに置く。
（`/_nuxt/`ディレクトリと`index.html`がビルドされるはず）


## 8. その他

### 疑問

#### `npm run generate`時に書き出し先ディレクトリの中身を削除したくない

- ビルドファイルをルートに配置＆VCCWを併用する場合に`nuxt generate`するとWordpressファイルが消えてしまうため
- 多分ここらへんで削除している  
  ref: https://github.com/nuxt/nuxt.js/blob/dev/lib/builder/generator.js#L105
- 考えられる対応？①：generate時にディレクトリの中身を削除しないようにする
- 考えられる対応？②：WPファイルは別ディレクトリに配置＆プロキシする

### サブディレクトリで使う際のディレクトリ設定

- `nuxt.config.js`の`generate`と`router`を変更する

```javascript
// example:
// ブラウザでの表示はhttp://localhost:3000/subdirectory
module.exports = {
  generate: {
    dir: 'dist/subdirectory' // デフォルトは`dist`
  },
  
  router: {
    base: '/subdirectory/'   // デフォルトは`/`
  }
}
```

# 参考

- [Nuxt.js](https://ja.nuxtjs.org)
- [Vue.js製フレームワークNuxt.jsではじめるUniversalアプリケーション開発 | HTML5Experts.jp](https://html5experts.jp/potato4d/24346/)