Nuxtで初めるWEBアプリ開発（SSR＆SPA）

Nuxt使ってサイトをリニューアルしたので色々まとめていきます。
使い方などは公式サイトが充実しているのでほかサイトでも説明があるため
Nuxtについてはサラッと流して困ったポイントをまとめていきます。

[clover.blue](https://clover.blue/)

## Nuxtって何？
* [Nuxt.js - ユニバーサル Vue.js アプリケーション](https://ja.nuxtjs.org/)
* [はじめに - Nuxt.js](https://ja.nuxtjs.org/guide#nuxt-js-%E3%81%A8%E3%81%AF%E4%BD%95%E3%81%8B-)

Vueを使って、最初の設定周りすっとばして開発が初めれる便利ツールです。

Vue単体でも、webpackとかあまり気にせず作れますが
さらに + でrouterやvuexも最初から揃っているのでそれほど気にせずに作れちゃうところが良いなと思いました。

## 使ってみて
もう個人的には **静的ページ** 、 **SSP** 、 **SSR** どれで開発するときもNuxtを使えばいいのではと思いました。
公式もかなり充実してるので、困ることがすくないのもよいところです。

## はじめる
公式が充実してるので下記から、そのまま順番通りに進めていけば特に詰まることなく初められると思います。

* [インストール - Nuxt.js](https://ja.nuxtjs.org/guide/installation)


### リニューアルにあたっての構成
下記のような構成ではじめました。

	npx create-nuxt-app <project-name>
	
	Choose the package manager * Yarn
	Choose UI framework * None
	Choose custom server framework * Express
	Choose Nuxt.js modules * Axios, PWA
	Choose linting tools * ESLint, Prettier, Lint staged files
	Choose test framework * Jest
	Choose rendering mode * Universal (SSR)

### Nuxtのディレクトリ構造について
ディレクトリ構造には意味があり下記に詳しく書いてあります。

* [ディレクトリ構造 - Nuxt.js](https://ja.nuxtjs.org/guide/directory-structure)

## 開発を初める
### とりあえず起動してみる
	yarn dev

http://localhost:3000を開くとdemoが表示されます。

個人的にport3000が、他の開発と被る可能性があるため変えるようにしています。
nuxt.config.jsに下記を追加しました。

	server: {
	  port: process.env.PORT || 1341
	}

process.env.PORTはherokuやGoogle App Engineなどにdeployする際に環境変数として定義されているので指定しています。
今回リニューアルにあたりGoogle App Engineを使っています。

## タイトルをページごとに変更したい
下記を参考にして設定しました。

* [Nuxt.js で動的タイトル設定](http://www.kaasan.info/archives/4309)
* [nuxtでtitleタグを動的に設定する](https://polidog.jp/2018/06/16/nuxt-head/)

## apiを作りたい
Expressが入っているため、nuxt.config.jsにserverMiddleware記述して
vueのrouterから外して、apiを定義することができるようになります。
下記を参考にしました。

* [API: serverMiddleware プロパティ - Nuxt.js](https://ja.nuxtjs.org/api/configuration-servermiddleware/)
* [Nuxtに「serverMiddleware」を設定して、API サーバ的な動きをさせてみた | 東京上野のWeb制作会社LIG](https://liginc.co.jp/438249)

### サーバー側もes6で書きたい
babel-nodeで実行しようと思ったのですがGAEではうまく実行できませんでした。
babel-nodeは本番での使用は推奨されていないようなので、一度変換してから実行するようにしました。
https://babeljs.io/docs/en/babel-node

#### es6でかけるようにpackage.jsonを変更する
dev環境では変換する必要がないため。babel-nodeをそのまま使っています.
本番環境では```build:server```を実行することで一度```server_dist```に変換します。
startの```server/index.js```を```node server_dist/index.js```に変更し。babelで変換したファイルを使うようにしました。

    "dev": "cross-env NODE_ENV=development nodemon --exec babel-node server/index.js --watch server",
    "start": "cross-env NODE_ENV=production node server_dist/index.js",
    "build:server": "babel server/ -d server_dist",

## 旧アドレスからリダイレクトさせたい
旧サイトはwww付きだったため。リダイレクトさせる必要がありました。
最初はGAEからリダイレクトさせる方法を考えていたのですが下記方法で実現しました。

https://github.com/nuxt/nuxt.js/issues/1843#issuecomment-360416960

middlewareに下記ファイルを置きwwwRedirect.jsを用意しました。

	export default function(data) {
	  const isWww = data.req && ~data.req.headers.host.indexOf('www')
	  if (isWww) {
	    data.redirect('301', `${process.env.HOST}${data.route.fullPath}`)
	  }
	}

そしてnuxt.configt.jsに書きを追加しました。
	
	router: {
	  middleware: ['wwwRedirect']
	},

## JSON-LDを管理
下記に詳しく書いてくれていますので参考にしました。

* [SEO に強くなる構造化データマークアップ  ~ Nuxt.js で JSON-LD をコンポーネント指向で管理する ~ - Qiita](https://qiita.com/ryota-yamamoto/items/2c43c606d9a96fc4de5f)

nuxt-jsonldというプラグインも作ってくれているので。使わせていただきました。
https://www.npmjs.com/package/nuxt-jsonld

<del>ただ。。あまり検証進められていないのですが。少し重くなる原因になっているのではと感じています。
リンクをするたびに動作が重くなっているように感じているので。時間があれば原因調べたいなと思っています。
濡れ衣だったらすみません。m(_ _)m</del>

こちら、1.4.4のバージョンで確認したところ問題なさそうです！
作者さんありがとうございます！

## GTMを使ってみる

下記プラグインを使うことで簡単に導入できます。

https://github.com/nuxt-community/modules/tree/master/packages/google-tag-manager

### GTM側の設定
ページビューでアナリティクスを設定しようとしたのですがSPA,SSRだとリンクをした際に計測されませんでした。
上記プラグインですと```nuxtRoute ```でイベントを発火してくれているため。
トリガをnuxtRouteにすることで遷移のタイミングで発火することができます。

* [Nuxt SPAのPVを @nuxtjs/google-tag-manager を利用して計測する - アクトインディ開発者ブログ](https://tech.actindi.net/2018/11/02/084447)
* [Nuxt.jsでGoogle Tag Manager+Google Analyticsを使ってみた - くらげになりたい。](https://www.memory-lovers.blog/entry/2019/06/20/113000)

## Postcssを導入する
いままで個別で入れたりprecssを入れたりしていたのですが。
postcss-preset-envを使っていくのが良いかなと思ってます。

* [Nuxt ver.2 へプロジェクトを移行したときにCSSで対応したこと（PostCSS編） - Qiita](https://qiita.com/viverra/items/bb1fcd2f527be2f5b205)

## Mockを導入する
ネット環境がなくても開発が行えるようにaxios-mock-serverを使ってmockを用意することにしました。
下記に@nuxtjs/axiosとの連携方法も書いてあります。

* [RESTfulな「axios-mock-server」の使い方 - Qiita](https://qiita.com/m_mitsuhide/items/b8e073cba0dae5af2359)

注意点は、```import axios```でnuxt外のaxiosを使わないことです。
そうすると@nuxtjs/axiosを使っていないためmockが反応しませんでした。

	import axios from 'axios'

	axios.get(`/url`)

下記のようにすることで解決しました。

	this.$axios.get(`/url`)
	
package.jsonにmockで起動できるようにscriptを追記しました。

    "dev:mock": "axios-mock-server -b && cross-env NODE_ENV=development MOCK=true nodemon --exec babel-node server/index.js --watch server",

nuxt.config.jsにmock用のプラグインをdev環境だけ追加するように追記しました。
MOCK=trueの場合のみ追加するようにしています。

	plugins: [
	  '~/plugins/jsonld',
	].concat(process.env.MOCK ? '~/plugins/mock' : []),

## e2eテストを導入する
cypressを入れてみました。

* [cypressを触ってみた - Qiita](https://qiita.com/okitan/items/b44882e28006c1be32b7)

### eslint, prettierでコケちゃう
eslint-plugin-cypressを入れて回避しましょう。

	yarn add eslint-plugin-cypress

.eslintrc.js

	extends: [
	  '@nuxtjs',
	  'prettier',
	  'prettier/vue',
	  'plugin:cypress/recommended', //追加しました。
	  'plugin:prettier/recommended',
	  'plugin:nuxt/recommended'
	],

* [Cypress 導入の方法まとめ - とろろこんぶろぐ](http://oisham.hatenablog.com/entry/2019/07/20/193902)

## feedを追加する
@nuxtjs/feedを使うと動的にも出力できてよさそうです。

https://github.com/nuxt-community/feed-module

* [Nuxt.js の静的生成で作ったブログに RSS2.0 を生やす方法 - Qiita](https://qiita.com/0x50/items/7bdf3e4308d61c5dbb85)
* [nuxtjs/feedで実装したRSSフィードをRSS2.0からATOM1.0にする | カオスボーイ・トーキョー](https://chaos-boy.tokyo/posts/2019-06-12/rss2_to_atom1/)

## sitemapを追加する
@nuxtjs/sitemapを使うと動的にも出力できてよさそうです。

https://www.npmjs.com/package/@nuxtjs/sitemap

* [Nuxt.jsで動的ページ含め、サイトマップ(sitemap.xml)を自動生成する方法 – こまめ](https://mameko.jp/197/)

### なぜだかGoogle Search Consoleにsitemap.xmlが反映されない
「サイトマップ 取得できませんでした」と出てしまい、サイトマップがうまく読み込まれませんでした。
フォーマットなど調べてみたのですが、いまのところ原因がわかりませんでした。
進捗があり次第。追記したいと思います。

## Adsenseの導入

下記プラグインを使うと、任意の位置に広告を追加することができます。
* https://www.npmjs.com/package/@nuxtjs/google-adsense


```js:nuxt.config.js
{
  modules: [
    // Simple usage
    ['@nuxtjs/google-adsense', {
      id: 'ca-pub-###########'
    }]
 ]
}
```

任意の位置に下記タグを入れます。

```vue
<adsbygoogle
  ad-slot="0000000000"
  ad-format="auto"
  full-width-responsive="true"
/>
```
0000000000には任意の`slotId`を入れましょう。

* [Nuxt.jsのプロジェクトでGoogleアドセンスの広告を表示させる | 大阪市天王寺区SOHOホームページ制作 | デザインサプライ-DesignSupply.-](https://designsupply-web.com/knowledgeside/5151/)

## 画像差分比較を実装してみる

componentを変更したときにどこまで影響があるのかが分かりづらくなる時があるためResemble.jsを使って画像の差分比較をしてみました。

下記手順をふむことで複数枚画像が存在した場合に一つ前の画像と差分を比較する仕組みを実装しています。


1. cypressでscreenshotを実行するとキャプチャをとる
2. なにかコンポーネントを修正する
3. もう一度cypressでscreenshotを取る
4. yarn dissする

詳しく記事にしましたので下記を見てください。
* [CypressとResamble.jsを使ったwebサイトの差分比較 - Qiita](https://qiita.com/kamem/items/d7577de327d1851f5c18)

下記参考にさせていただきました。
* [PuppeteerとResemble.jsを使ったスクショ比較によるピクセル差分テスト - Qiita](https://qiita.com/iHideck/items/a8b87cc800e72b37fc6e)


## youtubeでプレーヤー表示

vue-youtubeを使うと簡単に実装できそう

[Nuxt.js 2でYoutubeプレイヤー埋め込み - Qiita](https://qiita.com/n0bisuke/items/d8ae0a9ca23a691a439e)

Google code-prettifyを使ったときの不具合



## 今後対応したいこと
- push通知の実装
- ドロワーメニューの実装（良い感じのコンポーネントが見つからなかった…）
- Google Search Consoleでsitemapが読み込めない問題の解決
- header下にスクロールしたら引っ込むようにする（これも簡単なのが見つからなかった）プラグインを作ろうかなと思っています
- WAI-AREA roleを適切にいれる