Nuxt.js(v2.6.x)やっておきたい設定：その1/3｜create-nuxt-app〜各種プラグインの導入まで。

本稿は「Nuxt.js(v2.6.x)やっておきたい設定シリーズ」の第1段です。

- [その1/3｜create-nuxt-app〜各種プラグインの導入まで。](https://qiita.com/amishiro/items/1c2a009cb0470cf3223a)
- [その2/3｜SEOに必要なmetaとogpの設定及びpwa(Manifest、Icon、Workbox)の設定](https://qiita.com/amishiro/items/e668be423a85c2b61696)
- [その3/3｜コンポーネントフィアルの管理方法とloading・各種トランジションの設定](https://qiita.com/amishiro/items/1f768628e3b7267466c2)

---

「Nuxt.jsやっておきたい設定：その1/3」として、サイト制作やアプリ開発などに入る前にやっておきたい設定をまとめた。「[その2/3](https://qiita.com/amishiro/items/e668be423a85c2b61696)」では、Workbox、Manifest、Meta、Icon、Ogp（OneSignalはサーバーが関わるの本稿ではやらない）などのSEOやPWAに係る部分を記載。「その3/3」になって、やっとコンテンツ部分に入ってコンポーネントとか。

とりあえず、以下「その1/3」の設定をすれば、中規模程度までの開発に困ることは少ない…はず。フレームワークは何かと便利なBuefy（Bulma）を利用しています。開発も活発なのでBulma良いんじゃないかな。うん、ブルマはよいものです。

さて、楽しんで学んでいきませう。

## creat-nuxt-appインストール時の設定

`create-nuxt-app`でインストールするときの設定は以下。

```npm
? Project name amiTemplate-nuxt
? Project description Amiten's tremendous Nuxt.js project
? Use a custom server framework express
? Choose features to install Progressive Web App (PWA) Support, Linter / Formatter, Axios
? Use a custom UI framework buefy
? Use a custom test framework jest
? Choose rendering mode Universal
? Author name Amiten
? Choose a package manager npm
```

大事なことなので最初に…

### rendering modeは「Universal」を選ぶ。

rendering modeは「Universal」を選ぶ。特別な事情がなければSPAは選ばない。generate（静的書き出し）前提でも「Universal」を選ぶ。

### 他設定

- name & description & Author name
  案件にあわわせて適当に。

- server&test framework
  案件に合わせて適当に…決まっていなければ利用者の多いexpressとjestを選ぶ。（初期設定をインストール時にしてくれるので最初に入れておくと手間が減る。使わなければ後で削除すればいい。）

- UI framework
  案件に合わせて適当に…決まっていなければBuefyを選ぶ。カスタマイズがしやすく軽量で~~且つブルマと合法的に連呼できるので~~おすすめ。

- features
  案件に合わせて適当に…ESLintは基本として入れたいので、Linter / Formatterを選択。また、他決まってなければ、PWA、axiosあたりを入れておく。（初期設定をインストール時にしてくれるので最初に入れておくと手間が減る。使わなければ後で削除すればいいが、なんだかんだで使うと思う。）prettierは好みがかなり分かれるので外す。

- package manager
  案件に合わせて適当に…でも基本はnpmで統一。yarnも優秀で個人的には好きだけど、初学者向けにnpm選んどいたほうが良い（新しい人が入ってくる度に説明や設定頼まれると意外と時間取られるため）。

Nuxt.jsの初回インストールが済んだら、一度commitをしておく。


## 既存npmパッケージのアップデート

npm-check-updates(v3)を利用してpackage.jsonのアップデートを行う。
v2以前のバージョンをグローバルに入れている人を結構見かけるので、念の為、最新をプロジェクト用にインストールしてからアップデートをかける。

```terminal
npm i -D npm-check-updates
```

```terminal
npx ncu -u
```

npm-check-updates(v3)からbeta版などは対象に含まれないため、もしbeta版を利用したい場合は個別で書き換える。まずは、`npm outdated`で更新確認。

```npm
npm outdated

結果
↓
Package              Current          Wanted         Latest  Location
@nuxtjs/pwa            2.6.0           2.6.0  3.0.0-beta.14  amiTemplate-nuxt
babel-core    7.0.0-bridge.0  7.0.0-bridge.0         6.26.3  amiTemplate-nuxt
babel-eslint           8.2.6           8.2.6         10.0.1  amiTemplate-nuxt
babel-jest            23.6.0          23.6.0         24.7.1  amiTemplate-nuxt
jest                  23.6.0          23.6.0         24.7.1  amiTemplate-nuxt
```

今回は、既存バージョンだとエラーを吐き出す@nuxtjs/pwaを更新する。package.jsonから該当の項目を削除。

```package.json
{
  "dependencies": {
    "@nuxtjs/pwa": "^2.6.0" <-これを削除
  },
  ...
}
```

そして、再度インストール。

```
npm i @nuxtjs/pwa
```

`npm-check-updates`をかけて問題なければOK。

```
npx ncu

結果
↓
All dependencies match the latest package versions :)
```

まだ続く…

きれいになったpackage.jsonに基づいて、npmパッケージをインストールを再度実行する。
はじめにpackage-lock.jsonを削除

```
rm package-lock.json
```

次に、node_modulesも削除

```
rm node_modules
```

npmパッケージのインストール

```
npm i
```

動作確認

```
npm run dev
```

OK。一度commit。

## プラグインなどのnpmパッケージを追加でインストールする

レッツ、一括インストール！
↓

```
npm i pug pug-loader pug-plain-loader node-sass sass-loader @nuxtjs/style-resources lodash csvtojson moment @nuxtjs/google-analytics @nuxtjs/google-tag-manager @nuxtjs/sitemap vee-validate vue-mq vue-scrollto vue2-perfect-scrollbar vue-rellax aos
```

インストールしたら一旦commit。後で各種設定をしていくので、各npmパッケージの概略を確認。

### フレームワーク系

カスタマイズがしやすく軽量なbuefyをベースにする。好みだとおもうけど、じゃまにならない程度に便利で~~ブルマと合法的に連呼できるので~~おすすめ。

- nuxt-buefy(create-nuxt-app時にインストール済み)

### 言語系

htmlの記述量を減らすためpug（旧jade）を採用。肥大化しがちなvueファイルをコンパクトに、学習コストもそれほど高くないのでおすすめ。また、cssはscssを採用。単純に仕様者が多く学習コストが低いため。合わせて、style-resocesをインストールしておくことで共通のvaliables(scss変数)をnuxt内で使い回せるようにしておく。

- pug
    - pug
    - pug-loader
    - pug-plain-loader
- scss
    - node-sass
    - sass-loader
    - @nuxtjs/style-resources

### データー整形・処理系

データー整形や簡易的なデーター処理に仕込んでおくと非常に助かる３種の神器。使わなければコメントアウトしておけばいい。中規模以上の開発をしたいのであれば覚えておいて損はない。LPマスターには必要ないと思う。

- lodash
- csvtojson
- moment

### @nuxtjsチーム系

axios、pwaは`create-nuxt-app`時にインストール済み。使うかどうかは案件次第。goole-analyticsやtag-managerは運用チームに確認しつつ選び、サイト制作であればsitemapぐらいは、初めから入れておきたい。

- @nuxtjs/axios(create-nuxt-app時にインストール済み)
- @nuxtjs/pwa(create-nuxt-app時にインストール済み)
- @nuxtjs/google-analytics
- @nuxtjs/google-tag-manager
- @nuxtjs/sitemap

### 便利系

ほぼ100%出番があるvue用plugin。説明は以下。

- vee-validate
  フォームのフロントバリデートに使う。buefyとの相性がよく、柔軟性もそこそこ。覚えておいて損はない。

- vue-mq
  media-query用にプラグイン。v-ifと連携させることが多い。cssフレームワークと命名規則やbreakpointsをあわせておくと気持ちいい。ssr対応でnuxtで使いやすくしてくれているのもポイントが高い。

- vue-scrollto
  スムーズスクロール系で一番使いやすいんじゃないだろうか。nuxtにも対応していることもポイントが高い。

- vue2-perfect-scrollbar
  みんな大好き、perfect-scrollbarのvueプラグイン版。これ無しでレスポンシブ対応とかスクロール調整関連で地獄を見る。


### パララックス系

パララックスというか…スクロールに合わせたDOMのアニメーション用。個人的には多様したくないが未だに要望が多い。どうせやるなら初めから入れておき、デザイナーやクライアントと仲良く作業したい。

- vue-rellax
- aos

## .gitignoreに追加しておきたい項目

基本ディフォルトで問題ない。Nuxtありがとう。ただ、更新毎にハッシュで出力されるデーターは含めたくないので、@nuxtjs/pwa及び@nuxtjs/sitemapで自動生成されるファイルを`.gitignore`ファイルに追加しておく。また、generate（静的書き出し）利用の場合はdistディレクトリ比較とかするので、dist_がつくディレクトリは含まれないようにしておく。

package-lock.jsonはお好みで。

```.gitignore
# Nuxt generate
dist
dist_*/

# Service worker
sw.*

# @nuxtjs/sitemap
sitemap.xml
sitemap.xml.gz

# package-lock.json
package-lock.json
```

ついでに、除外対象を事前にcommitしちゃった場合の対応を載せておく。

```
git rm --cached -r .
git add -A .
git commit -m ".gitignore 除外指定を変更"
git push
```

## ESLintの設定

ディフォルトのESLintの設定は、JavaScript Standard Styleをベースに、Vue用に一部カスタマイズされている。

↓で、修正箇所を表示して。

```
npm run lint
```

↓で自動で修正してくれる。

```
npm run lint -- --fix
```

Nuxtありがとう。ほとんどいじることが無いのだけど、ちょっとだけ`.eslintrc.js`に追加して個人好みにしている。

```.eslintrc.js
module.exports = {
  // ↓lodashがESLintに引っかからないようにする。
  globals: { "_": true },
  ...
  rules: {
    // ↓devlopmentのときだけconsole.logを許可する
    'no-console': process.env.NODE_ENV === 'production' ? 2 : 0,
    // ↓末尾のセミコロンを許容する。
    'comma-dangle': ['error', 'only-multiline'],
    // ↓空白行に対してwarnのみ出るようにする。
    'no-multiple-empty-lines': ['warn', {max: 1}]
  }
}
```

## IE11対応

対応したくないけど、しなければならない。そんな憂鬱なあなたに…

### package.jsonにIE11対応を明示する。

package.jsonにIE11対応を明示しておく。ディフォルトでは`last 2 version`が設定されている。なので、現状は何もしなくてもいいんだけど指定しておくと３年後の自分が喜ぶ。

```package.json
{
  ...
  "browserslist": [
    "last 2 version",
    "android >= 4.4",
    "IE 11"
  ],
  ...
}
```

以下で対応しているブラウザリストを一覧できる。どのブラウザに対応してるの？とか聞かれたら、出力されたブラウザリストを提示してあげよう。

```terminal
npx browserslist
```

### nuxt.config.jsを修正してautoprefixerを有効化。

nuxt.config.jsを修正してpostcssのプラグイン「autoprefixer」を有効することで、cssで自動にプリフィックスがつくようにする。他postcssのプラグインを使いたいのであればここに追加していくが、今回はscss利用前提にするので使わない。

```nuxt.config.js
{
  ...
  build: {
    // ↓Build内に以下を追加
    postcss: {
      plugins: {
        'postcss-preset-env': {
          // Doc: https://github.com/postcss/autoprefixer
          autoprefixer: { grid: true }
        },
      },
    },
    ...
  }
}
```

## 細かい設定に入る前にディレクトリ構成を変更・整理する

各プラグイン・コンポーネント・SEO周りの細々したこと調整する前に、いらないファイルの削除や、作業がよく行われるディレクトリをまとめていく。

### README.mdファイルを削除

各ディレクトリに含まれているREADME.mdはいらない。

```
rm ./store/README.md ./static/README.md ./plugins/README.md ./pages/README.md ./middleware/README.md ./layouts/README.md ./components/README.md ./assets/README.md
```

### Nuxt.jsの基本作業ファイルを一つのディレクトリ(srcディレクトリ）にまとめる。

ディレクトリ数が多いと軽微なミス（ファイル格納場所間違いなど）が発生する。また、初学者は知らないディレクトリが並んでいることに拒否反応が起きることもあるので、Nuxt.jsの基本作業ファイルを一つのディレクトリ(srcディレクトリ）にまとめる。
規模が大きくなってからの対応が厳しいので、プロジェクト立ち上げ時から対応しておくと良い。

nuxt.config.jsに作業ファイルの変更内容を追記

```nuxt.config.js
module.exports = {
  mode: 'universal',
  // ↓以下追加
  srcDir: 'src/',
  ...
}
```

作業フォルダをまとめる

```terminal
mkdir src
mv assets components layouts pages plugins static store middleware src/
```

動作確認

```
npm run dev
```

OK。commit。

## Buefyをカスタマイズする。

Buefyは「Bulma(CSSフレームワーク)」「Material Desgin Icons」「Buefyのコンポーネントセット」の3つで成り立っている。そのうちのBulmaの部分をプロジェクトに合わせてカスタマイズできるようにする。

### オプションでCSSをfalseに。

nuxt.config.jsに記載されているnuxt-buefyの設定に、`css:false`を追加してBulmaをOFFにする。

```nuxt.config.js
{
  modules: [
    // Doc: https://buefy.github.io/#/documentation
    ['nuxt-buefy', { css: false }],
    ...
  ],
}
```

### Bulmaのstyleをutilitiesとその他(core)に分ける。

utilities.scssには、Bulmaのベースとなるユーティリティ（変数等）を入れる。基本、こちらを変更・追記する（正確には、Bulmaで予め登録されている変数を更新していく。）

```assets/css/bulma/utilities.scss
// Bulmaのベースユーティリティ（変数等）
@import "~bulma/sass/utilities/initial-variables";
@import "~bulma/sass/utilities/functions";
@import "~bulma/sass/utilities/derived-variables";
@import "~bulma/sass/utilities/animations";
@import "~bulma/sass/utilities/mixins";
@import "~bulma/sass/utilities/controls";
```

core.scssには、カスタマイズ予定のutilities.scss＋その他のsassを読み込む。基本修正しなくていい。使わないものはコメントアウトする。Buefy独自のcssを忘れがちなので必ず入れる。

```assets/css/bulma/core.scss
/*! bulma.io v0.7.4 | MIT License | github.com/jgthms/bulma */

// 制作したutilities.scssを読み込み
@import "utilities";

// @import "~bulma/sass/base/_all"
@import "~bulma/sass/base/minireset";
@import "~bulma/sass/base/generic";
@import "~bulma/sass/base/helpers";

// @import "~bulma/sass/elements/_all"
@import "~bulma/sass/elements/box";
@import "~bulma/sass/elements/button";
@import "~bulma/sass/elements/container";
@import "~bulma/sass/elements/content";
@import "~bulma/sass/elements/form";
@import "~bulma/sass/elements/icon";
@import "~bulma/sass/elements/image";
@import "~bulma/sass/elements/notification";
@import "~bulma/sass/elements/progress";
@import "~bulma/sass/elements/table";
@import "~bulma/sass/elements/tag";
@import "~bulma/sass/elements/title";
@import "~bulma/sass/elements/other";

// @import "~bulma/sass/components/_all"
@import "~bulma/sass/components/breadcrumb";
@import "~bulma/sass/components/card";
@import "~bulma/sass/components/dropdown";
@import "~bulma/sass/components/level";
@import "~bulma/sass/components/list";
@import "~bulma/sass/components/media";
@import "~bulma/sass/components/menu";
@import "~bulma/sass/components/message";
@import "~bulma/sass/components/modal";
@import "~bulma/sass/components/navbar";
@import "~bulma/sass/components/pagination";
@import "~bulma/sass/components/panel";
@import "~bulma/sass/components/tabs";

// @import "~bulma/sass/grid/_all"
@import "~bulma/sass/grid/columns";
@import "~bulma/sass/grid/tiles";

// @import "~bulma/sass/layout/_all"
@import "~bulma/sass/layout/hero";
@import "~bulma/sass/layout/section";
@import "~bulma/sass/layout/footer";

// buefy用CSS
@import "~buefy/src/scss/buefy";

```

### core.scssを共通のcssとして登録する。

nuxt.config.jsにcore.scssを共通のcssとして登録する。

```nuxt.config.js
{
  css: [
    // Bulma Doc: https://bulma.io/documentation/
    '~/assets/css/bulma/core.scss',
  ],
}
```

### utilities.scssの変数やMixinをコンポーネントでも使えるようにする。

nuxt.config.jsにひと手間加えて、`@nuxtjs/style-resources`モジュール経由で、utilities.scssの変数やMixinをコンポーネントでも使えるようにする。

```nuxt.config.js
{
  // ↓modules内で@nuxtjs/style-resourcesを読み込む。
  modules: [
    ...
    // Doc: https://github.com/nuxt-community/style-resources-module
    '@nuxtjs/style-resources'
  ],
  // styleResources内でutilities.scssを読み込む。
  styleResources: {
    sass: [
      '~/assets/css/bulma/utilities.scss',
    ]
  },
}
```

これでカスタマイズの準備完了。まだ準備段階か…とくじけない。

### utilities.scssを修正

Buety公式の「[layout&element](https://buefy.github.io/#/documentation/layout)」に書いてあるものは、[Bulmaのドキュメント](https://bulma.io/documentation/)を参照。それ以外は[Buetyのドキュメント](https://buefy.github.io/#/documentation)を参照。

修正例を載せておく。

```assets/css/bulma/utilities.scss
// Bulmaのベースユーティリティ（変数等）
@import "~bulma/sass/utilities/initial-variables";
@import "~bulma/sass/utilities/functions";
@import "~bulma/sass/utilities/derived-variables";
@import "~bulma/sass/utilities/animations";
@import "~bulma/sass/utilities/mixins";
@import "~bulma/sass/utilities/controls";

// この下に上書きしたいベースユーティリティ（変数等）を記載していく。

// Typography -------------------------

// ↓追加フォントなどの外部CSSは、core.scssかnuxt.config.jsで読み込む
// YakuHanMP: https://cdn.jsdelivr.net/npm/yakuhanjp@3.0.0/dist/css/yakuhanmp.min.css
// Noto Serif JP: https://fonts.googleapis.com/css?family=Noto+Serif+JP:400,700&amp;subset=japanese

// 日本語用設定。sans-serifしかないので、serif書体も追加しておく。
$family-sans-serif: sans-serif;
$family-serif: "YakuHanMP", "Noto Serif JP", "Yu Mincho", "YuMincho", serif;

// ベースのfont-familyを登録
$family-primary: $family-sans-serif;
$family-secondary: $family-serif;

//フォントサイズを登録 -------------------------

// 16pxを基準にremで調整(Doc：http://www.standardista.com/px-to-rem-conversion-if-root-font-size-is-16px/)
$body-size: 16px !default;

// 日本語でよく使われるサイズに変更。
$size-1: 2.5rem; // 40px
$size-2: 2rem; // 32px
$size-3: 1.5rem; // 24px
$size-4: 1.25rem; //20px
$size-5: 1rem; // 16px
$size-6: 0.875rem; // 14px
$size-7: 0.75rem; // 12px

// 基本のフォントサイズを設定
$size-small: $size-7;
$size-normal: $size-5;
$size-medium: $size-4;
$size-large: $size-3;

// line-heightが1.5なので、日本語に合わせて広めに変更
$body-line-height: 1.6;


// brakepoints -------------------------------

// 個人的に好きなbreakpoints
$tablet: 667px;       //LG G3など、5.5incタイプの大型スマートフォン
$desktop: 970px;      //ipad縦 ipad横
$widescreen: 1360px;  //MackBook 12/Pro 13/Surface2/3/Pro/Nexus10
$widescreen-enabled: true !default;
$fullhd: 1344px + (2 * $gap) !default;
$fullhd-enabled: true !default;

// breakpointsメモ
// @include mobile {}          //until 666px
// @include tablet {}          //from 667px
// @include tablet-only {}     //from 667px and until 969px
// @include touch {}           //until 969px
// @include desktop {}         //from 970px
// @include desktop-only {}    //from 970px and until 1359px
// @include widescreen {}      //from 1360px
// @include widescreen-only {} //from 1360px and until 1407px
// @include fullhd {}          /from 1408px

// add Mixin
@mixin wrapper {
  box-sizing: border-box;
  position: relative;
  width: 100%;
  padding-right: $bm * 2;
  padding-left: $bm * 2;
  @include tablet {
    padding-right: $bm * 3;
    padding-left: $bm * 3;
  }
  @include desktop {
    margin-right: auto;
    margin-left: auto;
    max-width: $widescreen;
    padding-right: $bm * 4;
    padding-left: $bm * 4;
  }
  @include fullhd {
    max-width: $fullhd - 2 * $gap;
    width: $fullhd - 2 * $gap;
  }
}


// color-variable ------------------------------------
// secondary、thirdlyを追加して、カスタムカラーの幅を増やしています。

// 明るい色・暗い色
$light: #efefef;
$light-lighten: lighten($light, 15%);
$light-darken: darken($light, 5%);

$dark: #3C3C48;
$dark-lighten: lighten($dark, 10%);
$dark-darken: darken($dark, 10%);

// primary (ブランドカラー)
$primary: #0A428C;
$primary-invert: findColorInvert($primary);
$primary-lighten: #205aa2;
$primary-darken: darken($primary, 5%);

// secondary（ポイントカラー ※カスタム）
$secondary: #FA4988;
$secondary-invert: findColorInvert($secondary);
$secondary-lighten: lighten($secondary, 15%);
$secondary-darken: darken($secondary, 5%);

// thirdary（※カスタム）
$thirdly: #DEE5EE;
$thirdly-invert: findColorInvert($thirdly);
$thirdly-lighten: #EBF0F4;
$thirdly-darken: darken($thirdly, 5%);

//snsカラー（※カスタム）
$line: #1dcd00;
$line-invert: findColorInvert($line);
$facebook: #3B5998;
$facebook-invert: findColorInvert($facebook);
$twitter: #55acee;
$twitter-invert: findColorInvert($twitter);
$youtube: #EC3324;
$youtube-invert: findColorInvert($youtube);
$instagram: #CDA98A;
$instagram-invert: findColorInvert($instagram);

// 上記カラーを使えるようにする
$custom-colors: (
  "secondary": ($secondary, $secondary-invert),
  "thirdly": ($thirdly, $thirdly-invert),
  "line": ($line, $line-invert),
  "facebook": ($facebook, $facebook-invert),
  "twitter": ($twitter, $twitter-invert),
  "youtube": ($youtube, $youtube-invert),
  "instagram": ($instagram, $instagram-invert)
);
$colors: mergeColorMaps((
  "white": ($white, $black),
  "black": ($black, $white),
  "light": ($light, $light-invert),
  "dark": ($dark, $dark-invert),
  "primary": ($primary, $primary-invert),
  "link": ($link, $link-invert),
  "info": ($info, $info-invert),
  "success": ($success, $success-invert),
  "warning": ($warning, $warning-invert),
  "danger": ($danger, $danger-invert)
),$custom-colors);

// グラデーション(※カスタマイズ)
@mixin gradient {
  background: $primary;
  background: linear-gradient(to right, #35B8CB 10%,$primary 90%);
}

// color-text ------------------------------------

// text color
$text: #666666;
$text-strong: $secondary;

// Links
$link: $primary;
$link-hover: $primary-darken;
$link-invert: $primary-invert;
$link-focus-border: $primary;


// etc -------------------------
// その他自由に登録していく。

// base margin(※オリジナル)
$bm: 8px;

// radius
$radius-small: 2px;
$radius: 3px;
$radius-large: 8px;

// radiusを使えるようにする
$control-radius: $radius;
$control-radius-small: $radius-small;

```

これだけカスタマイズできれば困らないはず。もしダメだったら素直に自作して追加する。

## pluginの設定をしていく。

プラグインの設定は大きく分けて二通りある。

1. nuxt.config.jsに直接記載していく。
2. pluginsにファイルを作成して、nuxt.config.jsに読み込む。

1のパターンは既出していてnuxt-buefyや@nuxtjs/style-resourcesが該当する。@nuxtjsがついてればだいたい該当する。2のパターンは…まぁあれだ、これからやるので覚えてほしい。vue用プラグインが利用可能になるので制作の幅が広がる。

また、lodashやvue-scrolltoなんかは代表例なんだけど、1でも２でもどちらでもOKな場合もある。自分で調べて好きな方にすればいい。

### 確認までに上記を意識してもう一度設定していくプラグインを書き出す。

細かいオプションの設定は省いて基本の使い方のみ掲載する。

#### 1のパターン

- @nuxtjs/axios
- @nuxtjs/pwa
- @nuxtjs/google-analytics
- @nuxtjs/google-tag-manager
- @nuxtjs/sitemap
- lodash

#### 2のパターン

- vue-scrollto
- vue-mq
- vee-validate
- vue2-perfect-scrollbar
- vue-rellax
- aos
- csvtojson
- moment

## @nuxtjs/axios

何もしなくて良い。create-nuxt-app時にnuxt.config.jsに組み込まれている。もしかしたら近い将来[nuxt/http](https://http.nuxtjs.org/)に置き換わるかもしれないということだけ、心のノートにメモっておく。

nuxt.config.jsに記載したオプションを引き継いで使う場合は、`$axios`を使う。オプション詳細は[公式サイト](https://axios.nuxtjs.org/)を参照のこと

```js:asyncData
async asyncData({ $axios }) {
  const ip = await $axios.$get('http://icanhazip.com')
  return { ip }
}
```
```js:methods/created/mounted/etc
methods: {
  async fetchSomething() {
    const ip = await this.$axios.$get('http://icanhazip.com')
    this.ip = ip
  }
}
```

## @nuxtjs/pwa

何もしなくても最低限のことをやってくれる。create-nuxt-app時にnuxt.config.jsに組み込まれている…が、何も設定しない場合は、icon機能をfalseにしましょう。気づかずにnuxtのお山アイコンがmanifestに登録されていることも。

```nuxt.config.js
export default {
  modules: [
    // Doc: https://pwa.nuxtjs.org
    ['@nuxtjs/pwa', { icon: false }],
    ...
  ],
}
```

また、PWAは複数の技術の集まりであることを忘れてはならない。

PWA対応のアプリだよ！と言い切るには、オプションを設定し、PWA用のアイコンなど画像を用意し、PWA用のサイト・アプリ設計をしなければならない…と心のノートにメモっておく。しかし、@nuxtjs/pwaが入れておくだけでもキャッシュ戦略が大きく楽になるので「わざと入れない」という選択肢はない。

オプションは[公式サイト](https://pwa.nuxtjs.org/)を参照のこと。

## @nuxtjs/google-analytics or @nuxtjs/google-tag-manager

GAとGTMどっちを使うか、または両方使うかは運用チームに確認すること。すり合わせ、データー取得テストを事前にしておかないと「とれない！どうなってんだ！」とリリース後の疲れた身体には少々辛いお言葉が飛び交う。

~~事前に確認しろといっただろ~~

使い方は各GitHub参照のこと。

- [@nuxtjs/google-analytics](https://github.com/nuxt-community/analytics-module)
- [@nuxtjs/google-tag-manager](https://github.com/nuxt-community/modules/tree/master/packages/google-tag-manager)

```nuxt.config.js
export default {
  modules: [
    ['@nuxtjs/google-analytics', { id: 'UA-XXXXXX-X' }],
    // Doc: https://github.com/nuxt-community/modules/tree/master/packages/google-tag-manager
    ['@nuxtjs/google-tag-manager', { id: 'GTM-XXXXXXX' }],
    ...
  ],
}
```
## @nuxtjs/sitemap

Nuxtは巷にあるsitemapジェネレーターでxmlを生成できないので、事前に仕込んでおく。google検索の初回反映に大きく影響が出るので、オプションも丁寧に設定しておき。リリース後に[サイトマップの送信](https://support.google.com/webmasters/answer/183668?hl=ja)を必ずやるぞ！と心のノートにメモっておく。

オプションは[GitHub](https://github.com/nuxt-community/sitemap-module)を参照のこと。

```nuxt.config.js
export default {
  modules: [
    ...
    // Doc: https://github.com/nuxt-community/sitemap-module
    '@nuxtjs/sitemap'
  ],
  sitemap: {
    hostname: 'https://example.com',
    cacheTime: 1000 * 60 * 15,
    // gzip: true,
    // exclude: [
    //   含めたくないディレクトリがあれば追加
    // ],
    // routes: [
    //   自動生成ページがあれば追加
    // ]
  },
}
```

## lodash

10kとか軽くするために必要な関数のみimportする風習があるけど、それ以前にやることがいっぱいある。とりあえず全入れでいいと思うのは自分だけ？

Nuxt公式サイトの[Webpack プラグインを追加するには？](https://ja.nuxtjs.org/faq/webpack-plugins/)を参考にして導入する。webpackをimportすること、既出のESlintで`_`を許可すること、の2点を忘れずに。

```nuxt.config.js
const webpack = require('webpack')

export default {
  ...
  build: {
    plugins: [
      new webpack.ProvidePlugin({
        '_': 'lodash'
      })
    ],
  }
}
```

## vue-scrollto

ここから、pluginsの中にファイルを作って、nuxt.config.js内のpluginに登録していく。まずは、vue用プラグインで感覚を覚える。ちなみにvue-scrolltoはnuxtに正式に対応しているので、nuxt.config.jsにモジュールとしてオプションを記載することもできる。素晴らしい。

が、今回は、plaugins経由で読み込んで見る。

ファイル作成

```
touch src/plugins/vue-scrollto.js
```

vue-scrollto.jsに必要なこと記載する。

```plugins/vue-scrollto.js
import Vue from 'vue'
import VueScrollTo from 'vue-scrollto'

Vue.use(VueScrollTo, {
  // ↓以下オプション Doc: https://vue-scrollto.netlify.com/
  duration: 700,
  easing: [0, 0, 0.1, 1],
  offset: -150
})
```

nuxt.config.jsのplugins内に登録

```nuxt.config.js
module.exports = {
  plugins: [
    '~/plugins/vue-scrollto',
    ...
  ],
}
```

動作テスト

```src/pages/index.vue
<template lang="pug">
div
  nuxt-link(to="" v-scroll-to="{ el: '#test' }") click!
  .test#test スクロールした！
</template>

<style lang="scss" scoped>
.test {
  margin-top: 200vh;
}
</style>
```

OK。


## vue-mq

ブレークポイントを設定してくれるナウいやつ。今回は、Bulmaで変更したブレークポイントと合わせて修正をしてみる。だけじゃつまらないので、mixinを追加して使い勝手を良くしてみる。

ファイル作成

```
touch src/plugins/vue-mq.js
```

vue-mq.jsに必要なこと記載する。

```plugins/vue-mq.js
import Vue from 'vue'
import VueMq from 'vue-mq'

Vue.use(VueMq, {
  breakpoints: {
    mobile: 666,
    tablet: 969,
    desktop: Infinity,
    // fullhd: Infinity,
  },
  defaultBreakpoint: 'mobile'
})

Vue.mixin({
  data() {
    return {
      mobile: false, // until 666px
      tabletOnly: false, // from 667px and until 969px
      tablet: false, // from 667px
      desktop: false, // from 970px
    }
  },
  watch: {
    $mq() {
      this.mobile = this.$mq === 'mobile'
      this.tabletOnly = this.$mq === 'tablet'
      this.tablet = this.$mq === 'tablet' || this.$mq === 'desktop'
      this.desktop = this.$mq === 'desktop'
    }
  },
  mounted() {
    this.mobile = this.$mq === 'mobile'
    this.tabletOnly = this.$mq === 'tablet'
    this.tablet = this.$mq === 'tablet' || this.$mq === 'desktop'
    this.desktop = this.$mq === 'desktop'
  }
})
```

nuxt.config.jsのplugins内に登録

```nuxt.config.js
module.exports = {
  plugins: [
    '~/plugins/vue-mq',
    ...
  ],
}
```

動作テスト

```src/pages/index.vue
<template lang="pug">
div
  div {{ $mq }}サイズだよ
  div(v-if="mobile") mobileサイズだよ！
  div(v-else) 他のサイズだよ
</template>
```

OK。

## vee-validate

buefyに[公式で対応](https://buefy.org/extensions/veevalidate/)している上に、日本語対応も簡単なのでおすすめのフロントバリデート。自作する余力があるならバリデートの制度を高めることに時間を使ったほうがいいと思う。


ファイル作成

```
touch src/plugins/vee-validate.js
```

vee-validate.jsに必要なこと記載する。合わせて日本語対応をする。

```plugins/vee-validate.js
import Vue from 'vue'
import VeeValidate from 'vee-validate'
import VeeValidateJa from 'vee-validate/dist/locale/ja' // 「VeeValidate」標準の日本語ローカル情報を使用しています

// vee-validateの日本語
Vue.use(VeeValidate, {
  locale: 'ja',
  dictionary: {
    ja: VeeValidateJa
  },
  // events: ''
})
```

nuxt.config.jsのplugins内に登録

```nuxt.config.js
module.exports = {
  plugins: [
    '~/plugins/vee-validate',
    ...
  ],
}
```

動作テスト

```src/pages/index.vue
<template lang="pug">
div.content
  form
    table.table
      tbody
        tr
          th Email
          td
            b-field(
              :type="{'is-danger': errors.has('email')}"
              :message="errors.first('email')"
              )
              b-input(v-model="form.email.value" placeholder="例) @kurilon.co.jp" name="email" v-validate="'required|email'" :data-vv-as="'Email'")
  button.button(@click.prevent="validateBeforeSubmit()") 送信！
</template>

<script>
export default {
  data() {
    return {
      form: {
        email: {
          name: 'Email',
          value: null,
        },
      }
    }
  },
  methods: {
    validateBeforeSubmit() {
      this.$validator.validateAll().then((result) => {
        if (result) {
          alert('OKだよ！')
          return
        }
        this.$toast.open({
          message: '赤字で記載された項目を確認してください。',
          type: 'is-danger',
          position: 'is-top'
        })
      })
    },
  }
}
</script>
```

それっぽいものが悩まず作れる…OK。

## vue2-perfect-scrollbar

scrollをコントロールしたいときに必ずお世話になる[perfect-scrollbar](https://github.com/utatti/perfect-scrollbar)のvueプラグイン。自作しようとすると実機テストが必須になるところ、だいたいカバーしてくれるナウいやつ。


ファイル作成

```
touch src/plugins/vue2-perfect-scrollbar.js
```

vue2-perfect-scrollbar.jsに必要なこと記載する。今回はCSSも追加する。

```plugins/vue2-perfect-scrollbar.js
import Vue from 'vue'
import PerfectScrollbar from 'vue2-perfect-scrollbar'
import 'vue2-perfect-scrollbar/dist/vue2-perfect-scrollbar.css'

Vue.use(PerfectScrollbar)
```

nuxt.config.jsのplugins内に登録

```nuxt.config.js
module.exports = {
  plugins: [
    '~/plugins/vue2-perfect-scrollbar',
    ...
  ],
}
```

動作テスト

```src/pages/index.vue
<template lang="pug">
div
  .test-area
    perfect-scrollbar
      div.test つれづれなるまゝに、日暮らし、硯にむかひて、心にうつりゆくよしなし事を、そこはかとなく書きつくれば、あやしうこそものぐるほしけれ。（Wikipediaより）つれづれなるまゝに、日暮らし（１００文字）
</template>

<style lang="scss" scoped>
.test-area {
  width: 300px;
}
.test {
  width: 600px;
  background-color: $secondary;
}
</style>
```

OK。

## vue-rellax

vue-rellaxは、簡易的なパララックスを表現してくれる[rellax.js](https://dixonandmoe.com/rellax/)のvueプラグイン。工夫をすればサイト全体の雰囲気をコントロールすることも可能なので、デザイナーやクライアントとのやり取りをスムーズにするためにも、はじめから導入しておく。

ファイル作成

```
touch src/plugins/vue-rellax.js
```

vue-rellax.jsに必要なこと記載する。

```plugins/vue-rellax.js
import Vue from 'vue'
import VueRellax from 'vue-rellax'

Vue.use(VueRellax)
```

nuxt.config.jsのplugins内に登録

```nuxt.config.js
module.exports = {
  plugins: [
    '~/plugins/vue-rellax',
    ...
  ],
}
```

動作テスト

```src/pages/index.vue
<template lang="pug">
div
  .test
    .test-text
      div(v-rellax) ぱらららっくすぅ
</template>

<style lang="scss" scoped>
.test {
  height: 200vh;
  margin-top: 50vh;
}
.test-text {
  width: 100%;
  background-color: $light;
}
</style>
```

OK。

## aos

aosはスクロールアクション系プラグイン。見出しなどのワンポイント導入にはもってこいなので、初めから入れておく。

ファイル作成

```
touch src/plugins/aos.js
```

aos.jsに必要なこと記載する。ESLintに引っかかるため、eslintの設定を一部無視する記述を追加しておく。また、ページ推移した際に一度AOSを解除する記述をMixinで追加しておくと幸せになれる。

```plugins/aos.js
import Vue from 'vue'
import AOS from 'aos'
import 'aos/dist/aos.css'

// ↓eslintの設定を一部無視
/* eslint new-cap: 0 */

export default ({ app }) => {
  app.AOS = new AOS.init({
    // disable: 'phone'
    duration: 800
  })
}

Vue.mixin({
  watch: {
    '$route.path': function () {
      setTimeout(() => {
        AOS.refresh()
      }, 500)
    }
  }
})
```

nuxt.config.jsのplugins内に登録…だけど、aosはSSRに対応していないためオプションを追加する。

```nuxt.config.js
module.exports = {
  plugins: [
    { src: '~/plugins/aos', ssr: false },
    ...
  ],
}
```

動作テスト

```src/pages/index.vue
<template lang="pug">
div
  h1(data-aos="zoom-in") 見出し１
  .test
    h2(data-aos="zoom-in") 見出し２
</template>

<style lang="scss" scoped>
.test {
  padding-top: 120vh;
  padding-bottom: 50vh;
}
</style>
```

OK。

## csvtojson

最後は、[csvtojson](https://www.npmjs.com/package/csvtojson)をベースとした関数をどこでも使えるようにしてみる。プラグインを自作できるとやっとエンジニアっぽい仕事ができてる感があって楽しい。

ファイル作成

```
touch src/plugins/csvtojson.js
```

injectを使って、`$csvToJson`でどこでも関数を使えるようにする。

```plugins/csvtojson.js
import csvtojson from 'csvtojson'

export default ({ app }, inject) => {
  inject('csvToJson', (csv) => {
    // ↓以下処理はお好みで
    const nl2br = (str) => {
      return str.replace(/\n/g, '<br>')
    }
    return new Promise((resolve) => {
      csvtojson()
        .fromString(csv)
        .then((data) => {
          _.each(data, (row, index) => {
            _.each(row, (v, key) => {
              data[index][key] = nl2br(v)
            })
          })
          resolve(data)
        })
    })
  })
}
```

nuxt.config.jsのplugins内に登録

```nuxt.config.js
module.exports = {
  plugins: [
    '~/plugins/csvtojson',
    ...
  ],
}
```

動作テスト1(asyncData内で描画前に処理)

```src/pages/index.vue
<template lang="pug">
div
  pre {{ json }}
</template>

<script>
export default {
  async asyncData({ app }) {
    const csv = await app.$axios.$get('test.csv')
    const json = await app.$csvToJson(csv)
    return {
      json: json
    }
  },
}
</script>
```

動作テスト2(mounted内で描画後に処理)

```src/pages/index.vue
<template lang="pug">
div
  pre {{ json }}
</template>

<script>
export default {
  data() {
    return {
      json: null
    }
  },
  async mounted() {
    const csv = await this.$axios.$get('test.csv')
    const json = await this.$csvToJson(csv)
    this.json = json
  },
}
</script>
```

axiosと同じように書ける。こういうの気持ちいい。OK。

## moment

あれ？momentは？？

何かとエラーの起きやすい日付関連をよしなにしてくれる[moment](https://momentjs.com/)。頻出は多くないので、pages内で利用する方法を記載しておく。

```src/pages/index.vue
<template lang="pug">
div
  p {{ day }}
</template>

<script>
import moment from 'moment'
export default {
  data() {
    return {
      day: null
    }
  },
  mounted() {
    const date = new Date()
    const day = moment(date).format('YYYY.MM.DD')
    this.day = day
  }
}
</script>
```

このように、コンポーネントに個別で呼び出しても使える。そいうことも覚えておくとよい。

---

これで、やっと基本的な設定完了。「その2/3」では、Workbox、Manifest、Meta、Icon、Ogp（OneSignalはサーバーが関わるの本稿ではやらない）などのSEOやPWAに係る部分を記載予定。「その3/3」になって、やっとコンテンツ部分に入ってコンポーネントとか。

さて、時間が取れるだろうか…。