キング・クリムゾン.js【Guess.js】

[Ateam Hikkoshi Samurai Inc. & Ateam Connect Inc. Advent Calendar 2019](https://qiita.com/advent-calendar/2019/hikkoshi) 7日目は、19新卒@hinoraがお送りいたします。

みなさんはアニメジョジョ５部、見ましたでしょうか？
僕は今更ながら最近になって見終えました。（めちゃ面白かった）

物語の最後の敵、ディアボロのスタンド「キング・クリムゾン」の能力、とても強力ですよね...!

本人の説明によると...
> **『読める』**…… 動きの『軌跡』が読める……
**『未来への動きの軌跡』**が…

> **『キング・クリムゾン』**の能力の中ではこの世の時間は消し飛び……
そして全ての人間はこの時間の中で動いた足跡を覚えていないッ！

要するに
**1. 👁‍🗨 未来への動きを読む**
**2. ⌛️ 時間を消し飛ばす**

という二つの能力を持っているのですが、
今回はそれと大体同じ事ができる`Guess.js`をNuxt.jsに導入してみます。

*※Nuxtはv2.4以降、画面内のnuxt-linkのリンク先にPrefetchがかかるのでコンポーネントの先読みだけだとほぼ無意味です；；*

## Guess.jsとは？
[Guess.js(GitHub)](https://github.com/guess-js/guess)

分析モデルや機械学習モデル、GoogleAnalyticsなどのデータを利用してユーザーがアクセスするページを予測して、プリレンダリング / プリフェッチしてくれます。
つまりは、「アクセスしたユーザーの**未来への動きを先読み**して、**(読み込み)時間を消しとばす👊**」事ができるのです！

## 👁‍🗨 未来への動きを読む
ユーザーがアクセスするページを予測します。
今回の予測データにはGoogleAnalyticsのデータを利用していきます。

### パッケージ追加
```bash:package
yarn add -D guess-webpack
```

### 設定
```javascript:~/nuxt.config.js
import { readFileSync } from 'fs';
import { GuessPlugin } from 'guess-webpack';

export default {
// ...省略
  build: {
    extend(config, { isClient }) {
      if (isClient) {
        const guessOptions = {};
        if (GA) {
          guessOptions.GA = 'xxxxx'; // GAのビューID
        } else {
          guessOptions.reportProvider = () =>
            // Fallback
            Promise.resolve(JSON.parse(readFileSync('./routes.json')));
        }
        config.plugins.push(new GuessPlugin(guessOptions));
      }
    },
  },
}
```

GAから読み込めなかったときのフォールバック用JSON

```~/routes.json
{
  "/": {
    "/dog": 80,
    "/cat": 20
  },
  "/dog": {
    "/": 20,
    "/cat": 80
  },
  "/cat": {
    "/": 80,
    "/dog": 20
  }
}

```

`GuessPlugin`のオプションにGoogleAnalyticsのビューIDをセットします。
フォールバックとして手動でprobabilitiesを設定したroutes.jsonを読み込みます。

設定が終わったら１度`yarn build`します。
そうするとGAデータ読み出しの為にGoogleアカウントの認証が走るので、内容を確認して承認します。


ここで試しに

```vue:index.vue
<template lang="pug">
  ul.list
    li
      nuxt-link(to='/dog') Dog
    li
      nuxt-link(to='/cat') Cat
</template>
<script>
  import { guess } from 'guess-webpack/api';

  export default {
    computed: {
      probabilities() {
        return guess();
      },
  },
};
</script>
```

上記のようにしてVue.jsDevToolsなどでprobabilitiesを見てみると、ユーザーの遷移先予測データをみる事ができます。
![ss.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185436/5db721cf-2f0e-3b9f-3da8-fd467dbcc0d5.png)

**『読める』**…… 動きの『軌跡』が読める……


## ⌛️ (読み込み)時間を消しとばす
plugins配下に新しくファイルを作ります。

### プラグイン
```javascript:~/plugins/guess.js
import Vue from 'vue';
import { guess } from 'guess-webpack/api';

export default ({ app: { router } }) => {
  router.afterEach(to => {
    Vue.nextTick(() => {
      const predictions = Object.keys(guess()).sort(
        (a, b) => a.probability - b.probability
      );
      predictions.forEach(path => {
        router.getMatchedComponents(path).forEach(Component => {
          if (typeof Component === 'function') {
            try {
              Component(); // ⏳ -> ⌛️
              //Other
            } catch (e) {}
          }
        });
      });
    });
  });
};
```

`guess()`でGAのデータから遷移先を予測して、遷移確率の高い順に`Component()`で該当ページのコンポーネントを読み出しています。
また他のイベントも実行する余地があるので、遷移予想先に対して何かする場合に有効そうです。

DevToolsのNetworkタブで確認すると、遷移予想先の`index.js`が読み出されている事が確認できます。[^1]


>これが我が『キング・クリムゾン』の能力！
『(読み込み)時間を消し去って』飛び越えさせた・・・！！（親切）

一応[デモ](https://guess-king-crimson.web.app/)も作ったので置いておきます

みなさんも`Guess.js`で素敵なディアボロ体験を！


## 🚩参考サイト
- [公式 - 導入ドキュメント](https://guess-js.github.io/docs/)
- [Monotalk - guess-webpack を使う](https://www.monotalk.xyz/blog/Using%20guess-webpack/)

公式ドキュメントには他にも静的ページ、Reactなどへの導入方法も紹介されています。

---

明日は同期の@wakky_404です。
何書くのか全く聞いてないので、僕も楽しみです


[^1]: nuxt-linkにno-prefetch付けないとGuess.jsによるものか確認できないです