Vue.jsでアプリケーションを開発するときによくある質問集

#概要
Single Page Applicationを実装するにあたって、気になることの質問・回答集。
ここで言う「Single Page Application」とは、画面遷移（リロード）をせず、１ページ内で
ajaxなどを使用してページ遷移（のような動き）を実装しているものを指します。
また、Vue.jsを使用して実装することを想定しています。
※随時更新していきます。

#FAQ
## Google Analyticsの測定はできるの？
可能です。
vue-routerでURLを切り替える際に、手動でGA側にページ遷移を通知することで測定されます。
（ブラウザバックではページカウントが増えません）

任意のイベントを通知することも可能ですが、懸念点としては下記が挙げられます（未検証）

- GAタグ以外で、手動でページ遷移を通知する方法がない計測タグは対応できない
- Google Tag Managerを使ってページごとに任意の処理を行いたい場合、対応できない可能性がある

#### 参考
https://developers.google.com/analytics/devguides/collection/gtagjs/single-page-applications
http://sys1yagi.hatenablog.com/entry/2016/11/30/233414
 
##  Googleにちゃんとindexされるの？
sitemap.xmlを設置してSearch Consoleで登録すればindexされます。
また、indexされたページもtitleやmeta情報などが反映されており、
Google側でjsが実行された状態でindexされます。

## sitemap.xmlの自動生成ツールは使えるの？
使えません。
sitemap.xmlを自動生成するツールは多数Web上にありますが、
SPAに対応してるものはありませんでした。

例：
http://www.sitemapxml.jp

なので、SPAの場合においては、sitemap.xmlを手動作成する必要があります。


## ページのURLを自由にカスタマイズできるの？
できます。
Vue.jsがもつvue-routerというモジュールがあり、ページURLと使用するモジュールを紐付けることができます。

* vue-router    
https://jp.vuejs.org/v2/guide/routing.html

URLに動的なパラメータを持たせることも可能です。
下記のページで商品URLの例を確認することができます
ただし、対応する場合はサーバー側でリライトモジュールの設定が必要です。


## 任意のパラメータを付与させることはできるの？
できます。
vue-routerではパラメータを下記の記載で取得可能です

```vuejs:code
{{ $route.query.name}}
```

参考：動的ルートマッチング
https://router.vuejs.org/ja/guide/essentials/dynamic-matching.html#%E3%83%91%E3%83%A9%E3%83%A1%E3%83%BC%E3%82%BF%E3%83%BC%E5%A4%89%E6%9B%B4%E3%81%AE%E6%A4%9C%E7%9F%A5

## 効果測定タグをページ毎に出し分けできるの？
できます。
ただし、ページ遷移をした時点でHTMLの評価は行われるようなので、
Vue.jsのif構文で表示制御をする必要があります。
コンバージョンなどについては当記事内の
「ブラウザバックで戻ったときにコンバージョンタグが複数回カウントされたりしないの？」
の回答を参考のこと

## title/metaをページ毎にカスタマイズできるの？
Vue.jsのプラグインである「Vue-Meta」を利用することで実現できます。

Vue-Meta
https://github.com/declandewet/vue-meta#recognized-metainfo-properties

このプラグインでは下記のことが可能です。

* titleをページ毎に書き換える
* metaタグ（keywords、description、OGPタグなど）をページ毎に設定する
* 任意のCSSファイル・javascriptファイルを読み込む
* nosriptタグを埋める
* html/bodyに属性を指定する


## ブラウザバックで戻ったときにコンバージョンタグが複数回カウントされたりしないの？
実装で回避することができます。
以下のような処理順で行うことで、重複カウントは防げます。
（下記は処理完了ページの例）

※処理完了ページの例
１）ページアクセス
２）APIにてセッションチェック
３）２がOKであれば、完了ページ表示フラグを立てる
４）コンバージョン用のHTMLが出力される

ブラウザバックでアクセスされた場合、２のチェックでエラーになるため、
３以降が行われることなく、エラーページが表示されます。
Vue.js内にHTMLとして普通に記載していると、セッションチェックが終わる前にHTMLを評価してしまうので、
出力フラグを用意し、そのフラグによって出力制御をすることで実現可能です。

## 各ページのアクセスログって残るの？
残りません。
Single Page Applicationはすべてクライアント側でHTMLの描画を行うので、サーバー側にログは残りません。
ただし、APIを呼び出したログは残ります。
SPA側で「ページ切り替えを行った」ということは検知できるので、その際にログ記録用のAPIに
URL情報を付与して送るなどしておけば、アクセスログを取ることは可能です。

例）
https://～.co.jp/api/accesslog.asp?url=/pd/cosme/test001

ログ記録用APIをわざわざ呼ぶと、APIコール１回分がコストになるので、セッション確認APIに
付与するようにするなどすればより良いです。

## そもそもSPAって早いの？
処理自体は変わっておらず、その処理をクライアント側で行うか、サーバー側で
行うかだけの違いなので、処理速度はクライアント側のPCスペックや通信環境に依存します。
SPAでは初回ロード時に必要なjavascriptファイル・CSSファイルはダウンロードされるため、
２ページ目以降の表示は早くなります。また、ヘッダー・フッターなど
共通の部分は最初のページのみでロードされるので、２ページ目以降は少し早くなります。

ただし、SPAではHTMLの構築をすべてjavascriptで行い、ページ遷移がないため、
メモリリークが発生するリスクがあります。
（構築されたHTML情報はメモリに展開されるため）
そのため、場合によっては任意のページでリフレッシュする方が良い場合もあります。
これは状況によるのでサイト毎に考えてください。

## SPAで多言語対応ってどうやるの？
Vue.jsのi18nプラグインで対応可能です。
https://qiita.com/_upto_me_/items/6d76dcd2d2c09b1bcb88

手順は以下の通り。

１）i18nプラグインをインストール
２）Vue.jsインスタンス生成時に多言語設定を追加
３）初期値のlocaleを設定
４）JSON形式のmessageファイルを作成
５）HTML内にmessage埋め込み
６）言語切替処理を実装

messageファイルは下記のような形式で作ります。

```json:message.json
{
    "ja": {
      "message": {
        "title": "タイトル",
        "dashbord": "ダッシュボード",
        "subtitle": "ここがサブタイトルになります"
      }
    },
    "en": {
      "message": {
        "title": "title",
        "dashbord": "Dashboard",
        "subtitle": "sub title"
      }
    },
    "han": {
      "message": {
        "title": "標題",
        "dashbord": "儀表盤",
        "subtitle": "副標題"
      }
    }
  }
```

言語毎にjsonファイルを分けることも可能です。
また、HTML内の記載はこうなります。

```html:html
<h1>{{$t("message.dashbord")}}</h1>
```

手順の３で設定したlocaleを「jp」や「en」に変更することで、
message.jsonに定義された言語に変わります。
`{{$t("message.dashbord")}}`の形式で記載されてない箇所は変わりません。

サンプル
http://spa-sample.ivp.co.jp/entry1
（ページ最上部の「ダッシュボード」が変わります）

## ページスクロールした位置って記憶してるの？
記憶してます。下記のような動作になります。

１）検索結果ページでページ下部までページスクロール
２）別ページへ遷移
３）ブラウザバックで戻る
４）ページ下部で表示される

また、ブラウザバックではなく、リンクで戻った場合はページ最上部に行きます。

１）検索結果ページでページ下部までページスクロール
２）別ページへ遷移
３）リンクで商品一覧に戻る
４）ページ最上部で表示される

## セキュリティでCSRF対策はどのようにすればよいか？
基本的にはサーバーサイドで制御するときと同じです。

１）入力確認画面でトークンを発行する
２）完了画面で１で発行したトークンが生きてることを確認する
３）２がOKであれば登録処理を行い、１のトークンを無効化する

この内容で完了画面への直接アクセス（CSRF）は防げます。
確認画面でのトークン発行は「登録完了」Buttonを押下したタイミングで発行します。
なので、確認→完了のあたりの処理順は下記のようになります。

１）確認画面表示
２）完了画面へ進むボタンクリック
３）トークン発行APIをコール（この時点ではURLは確認画面のまま）
４）完了画面へ遷移
５）登録APIをコール
６）３のトークンが無効化
７）直接完了画面にアクセスしてもトークンがないのでエラーになる

参考情報として、
Laravel(PHPフレームワーク)では、サーバ側でCSRFトークンを発行する形で対応しているようです。
http://blog.asial.co.jp/1496

## sitemap.xmlは設置できるの？
設置可能です。

ただし、vue-cliを使ってドメイン直下にファイルを置く場合には、
vue-routerでのルーティング設定か、webpackの設定調整が必要です。
上記サイトではwebpackの設定を調整したので、
staticフォルダ以下に配置しています。

## 拡張子の制限はないの？
ありません。

## faviconを設置したいんだけどこに置けばいいの？
sitemap.xmlや画像フォルダと同じ場所におけばOKです。

## httpステータスコードは制御できるの？
できません。
SPAの場合は大本になってるファイルがあり、その中で仮想的にHTMLを構築するため、
存在しないページURLでアクセスされても、200が返却されます。
200が返却された後、ページ表示処理で404のような表示をすることは可能ですが、
httpステータスコード自体を404にすることは不可能です。

## ファイル更新したときにキャッシュはどう処理されるの？
色んなアプローチがあると思いますが、Vue.jsではWebPackという技術を使用することで回避しています。
Vue.jsには、vue-cliという開発するためのツールや設定がまとまったものがあるのですが、
その中にwebpackの設定が同梱されています。

**vue-cli**
https://jp.vuejs.org/2015/12/28/vue-cli/

vue-cliに含まれてるwebpackの設定では、複数のjsファイルやcssファイルを
結合して出力する際、ソースの内容からハッシュ値を生成しファイル名に付与します。

たとえば、

![adbeebb4-c790-9c75-6a9b-93d750adb3f2.png](https://qiita-image-store.s3.amazonaws.com/0/23578/9520ee42-305d-c687-68fe-6c1ba15db532.png)


この状態からvue.jsで管理されているhtmlに修正をいれてbuildしなおすと

![てｓｔ.png](https://qiita-image-store.s3.amazonaws.com/0/23578/254ea560-dc41-6a29-b1e0-62cc57e707a7.png)

こうなります。
変更が入っていないファイルはそのまま、で変更が入っているファイルはハッシュ値が変わっています。
これでキャッシュされることはありません。

ただし、これはwebpackで管理されているファイルだけなので、webpackの管理外に
なっているファイルは、ハッシュ値の付与がされないので、キャッシュの問題が発生します。
完全に回避しようとすると全てをwebpack管理する必要がありますが、
ルーティングに関するjsファイルは標準でwebpack管理されているので、
ページ遷移できないなどのリスクは少ないのでは・・・・と考えています。

#その他
質問などあればコメントに書いていただければと思います！
判明したものから随時アップデートしていきます！