Vue.js から Nuxt.js への移行

この記事は [ShoTime Advent Calendar 2018](https://qiita.com/advent-calendar/2018/shotime) の 3 日目の記事です。

Firebase から取得した情報を Twiiter カードで表示させるため、Nuxt.js を導入した際の記録です。Nuxt.js の Universal モードを利用し、ユーザーが投稿した内容にユニークな URL を与え、Twitter カードで画像を表示させています。

![a.jpg](https://qiita-image-store.s3.amazonaws.com/0/62259/7a051bd7-ff33-3e1f-c5d1-bb1ea9b0dc26.jpeg)


## Vue.js から Nuxt.js 移行への歴史
[ShoTime（目標達成シート）](https://shotime.now.sh/)は 2018年4月8日に企画がスタートしてから次のような時間軸で Vue.js から Nuxt.js へ移行してきました。

| 年月日 | 概要 |
|:-:|:-:|
| 2018/8/29 | Vue.js から Nuxt.js (nuxt-edge) へ |
| 2018/9/22 | Nuxt.js v2 |
| 2018/10/18 | Nuxt.js v2.2 |

Vue.js では、Twitter で URL を引用したツイートを行った時に、 metaタグを SSR していないため Twitter上で　metaタグが正しく表示されませんでした。
（Google は SSR していなくても読んでくれるので Twitter も・・・と期待していたのですがダメでした）

## 初めて Nuxt.js を触る

Nuxt.js を、かるーく触った印象は、「おっ、以外と簡単かも！」という感じでした。プロジェクトの規模が小さかったこともあり、Vue.js から Nuxt.js への移行は非常に簡単でした。

### Vue.js での環境

- Netlify
- Vuex
- Vue Router
- Element UI
- Firebase
- Vuefire

### Nuxt.js での環境

- Now.sh
- Vuex
- Element UI
- Firebase

## Nuxt.js について調べたこと
- ドキュメント一通り
- Github にあるサンプルコード

## 認証制御

Vue.js では、router で beforeEnter を使って認証制御していましたが、Nuxt.js では、middleware というフォルダに、`authenticated.js` というファイルを作り、コンポーネントから、ミドルウェアを指定します。

```js
middleware: 'authenticated',
```

## require と import を使い分ける
Canvas を フロントエンドでも、Node.js でも同じコードを利用したかったのですが、ビルド周りでうまくいかずに、結局あきらめてほとんど同じようなコードで、`require` のための　`module.exports`　と `import` のための `export default` を書きました。

## Nuxt.js が Vue.js と異なる特徴
- **規約** がもたらす統一感
- pages 内の　`.vueファイル` がそのままルーティングになる
- asyncData を利用できる
- head() で SSR 時の SEO 対策ができる

## Nuxt.js のここが難しかった

- 認証
- 3種類のモード

## 認証

Twitter 認証を実装するさいに、Nuxt.js のライフサイクルをしっかり理解する必要がありました。

 ![nuxt-schema.png](https://qiita-image-store.s3.amazonaws.com/0/62259/16ee6875-66f7-7e1e-2d4b-4421359a0033.png)

 [Nuxt.js 公式ドキュメント参照](https://ja.nuxtjs.org/guide#%E5%9B%B3%E8%A7%A3)

この図にあるサイクルだけではなく、全てのリクエストはブラウザから始まり、キャッシュの Expire の存在も考慮し、またユーザーがキャッシュを消す可能性も考慮した実装が求められます。Twitter 認証の場合、リダイレクト先が 認証を実行したページだったりしたので、そこのページを表示する際には Twitter からのリダイレクトではないか必ず確認する必要もあります。このあたりについては公式のドキュメントだけでは少し情報が不足しているかもしれませんので、近くにいる Nuxt.js に詳しい人に聞くか、本を読むのがオススメです。ShoTime を実装する時に GitHub のリポジトリを読み漁りましたがあまり参考になるコードはありませんでした。

オススメの本はこちらです。[Nuxt.jsビギナーズガイド](https://www.amazon.co.jp/Nuxt-js%E3%83%93%E3%82%AE%E3%83%8A%E3%83%BC%E3%82%BA%E3%82%AC%E3%82%A4%E3%83%89%E2%80%95Vue-js-%E3%83%99%E3%83%BC%E3%82%B9%E3%81%AE%E3%83%95%E3%83%AC%E3%83%BC%E3%83%A0%E3%83%AF%E3%83%BC%E3%82%AF%E3%81%AB%E3%82%88%E3%82%8B%E3%82%B7%E3%83%B3%E3%82%B0%E3%83%AB%E3%83%9A%E3%83%BC%E3%82%B8%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E9%96%8B%E7%99%BA-%E8%8A%B1%E8%B0%B7-%E6%8B%93%E7%A3%A8/dp/4863542569) 
この本を読んで Nuxt.js の基礎を抑えつつ、サンプルコードも配布されていたので、そのコードも非常に参考になりました。


## 3種類のモード

- Universal
- Generate
- SPA

これら３つのモードを適切に理解し、どのモードを使うべきかを判断することが Nuxt.js を使い始める際の最初に考えるべきことかもしれません。

**Universal** はサーバーが必要です。Universal を使うことで動的なルーティングに対応できます。例えばユーザーが投稿した内容に対して１つのユニークな URL を割り当てるようなサービスは Universal を使うことになります。Universal モードの場合、Netlify のような静的サイト配信サービスではなく Node.js が動くサーバーを用意する必要があります。

**Generate** は、静的サイトとして配信できるようにビルド時に、HTML, CSS, JavaScript に書き出されます。通常 Vue.js で書かれたコードの HTML には `<div id="app"></div>` のようなタグが一つだけあり、そこに対してブラウザ側で読み込んだ JavaScript で DOM を構築していきます。それに対して Generate モードは、事前にビルド時にすべてのルーティングを適切な HTML に吐き出すため、SEO対策が十分に可能となります。Generate モードでは動的な URL には本来対応できませんが、ビルドを定期的に行うことで、対応させたりするすごい人もいるようです。

**SPA** は、Vue と同じです。と言ってしまうと、じゃあ Vue でいいのでは？と思いますが、私は、Nuxt.js の SPA モードもおすすすめです。それは **規約** がもたらす統一はメンテナンスしやすく、他の会社の人、他のプロジェクトで書かれたコードであっても大きくアーキテクチャに差がでないため、新しいエンジニアがキャッチアップしやすくもあります。

[ShoTime（目標達成シート）](https://shotime.now.sh/)は **Universal モード** を利用しています。また ShoTime では配信サービスに [Now.js](https://zeit.co/now) を採用しています。無料版ではコードが公開されてしまいますので注意が必要ですが、最近、料金プランも変更され `0.99$/mo` から利用でき、使いやすくなったのでオススメです。（以前は、`15$/mo` からでした）

Now.js については、[ShoTime Advent Calendar 2018](https://qiita.com/advent-calendar/2018/shotime)にて他の日にご紹介できればと思います。