2019-12-09

Resource HintとGuess.js

kawakami

このブログで紹介したいこと

 Predictive PrefetchingライブラリであるGuess.jsを導入するまでを紹介したいのですが、そもそもPredictive Prefetchingとは何なのかわからなかったので、改めて、その前提であるResource Hintから紹介していこうと思います!

Resource Hintと4つのAPI

 Webの仕様の中には、リソースを事前に取得してページの読み込み速度を高速にする仕様があります。それはResource Hintsという仕様になりまして、そのうえのAPIの一つにPrefetchがあります。  Resource Hintには、Prefetchを含め4つのAPIがありますので、順番に紹介していきます。

dns-prefetch

 ドメインの名前解決を事前に解決しておくAPIになります。例えば外部サイトのJS、CSS、画像を使っていた場合に利用すると効果的です。

書き方

<link rel="dns-prefetch" href="//example.com">

HTML Elementのlink Elementを利用して書きます。 その動きをWEBPAGETESTを使ってみてみましょう。

Image from Gyazo

 dns-prefetchは、なるべく早く解決したほうが効果的になるため、設置場所は、Head Elementのなるべくはじめの方に書くのがおすすめです(Content-typeやTitleの直後など)

 ※ちなみにアクセスしているサイト(この場合でいうとkawakami.dev)に対してdns-prefetchを指定しても何も変化はありません、サイトにアクセスした時点で、すでに解決されているためになります。

preconnect

 preconnectは、dns-prefetchの処理にプラスして、TCPのハンドシェイク、TLSのネゴシエーションなども事前に行うAPIになります。

<link rel="preconnect" href="//example.com">

その動きをWEBPAGETESTを使って見てみましょう。

Image from Gyazo

preconnectはIEでは対応されておりません。そのため、以下のようにLink Elementを書くと、IEであってもdns-prefetchまでは行ってくれるようになります。

<link rel="preconnect dns-prefetch" href="//example.com">

ドメインを指定するのは一苦労

 dns-prefetch、preconnectで指定するURLは、そのページで指定する外部ドメインすべてを指定するのが望ましいです。しかし、そのドメインはHTMLにあったり、CSSにあったり、JSにあったりで調べるのが一苦労です。  おすすめは、WEBPAGETESTにはDomainsというタブがありまして、そこを見ていただくとそのサイトがアクセスしたドメインが一覧できるので、こちらからドメインを取得するのがおすすめです。

Image from Gyazo

prefetch

 ここまで紹介してきたAPI(dns-prefetch,preconnect)は、アクセスしたページで使用する外部リソースのためのAPIでした。  prefetchはそれとは違い、これからアクセスするであろうページのためのAPIになります。prefetchを使うとリソースを事前に取得することができます。

<link rel="prefetch" href="second.html" as="document">
<link rel="prefetch" href="assets/js/second.js" as="script">
<link rel="prefetch" href="assets/styles/second.css" as="style">
<link rel="prefetch" href="assets/images/pic03.jpg" as="image">

as属性は任意で指定することができまして、リソースに応じたコンテキストを指定することができます。as属性の一覧はコチラ

それでは動きをWEBPAGETESTを使ってみてみましょう。

Image from Gyazo ※またcrossorigin属性も任意でつけることができまして、CORSポリシーを設定することができます。

<link rel="prefetch" href="//example.com/next-page.html" as="document" crossorigin="use-credentials">

prerender

prerenderは、preconnectに加えて読み込んだリソースをキャッシュ上にレンダリングまで行います。それによりそのページにアクセスしたときに素早くページを表示させることができます。

<link rel="prerender" href="second.html">

それでは動きをWEBPAGETESTを使ってみてみましょう。 Image from Gyazo

魅力的なAPIですが、prerenderは1つしか設置することができません

preloadの紹介

 Resource Hintsの仕様には含まれないのですが、preloadというprefetchに似たAPIもありますので紹介します。  preloadはprefetchによく似ているのですが、prefetchは外部リソースの先読みに用いてたのに対して、preloadは現在アクセスしているページのリソースをなるべく早く読み込ませるために使用するAPIです。  例えば、Web Fontsなどなるべく早く読み込ませたほうが良いリソースに使うのがおすすめです。

<link rel="preload" as="font" type="font/woff2" href="//fonts.gstatic.com/s/pacifico/v16/FwZY7-Qmy14u9lezJ-6I6MmBp0u-zK4.woff2" crossorigin>

動きをWEBPAGETESTを使ってみてみましょう。

Image from Gyazo

prefetch、prerender指定の難しさ

 Resource Hintsの中でも、prefetch、prerenderは魅力的なAPIですが、サイト全体のリソースを指定しておけば良いわけではありません(prerenderはそもそも1つしか指定できない制約があります)。ユーザーが次に訪れるであろうページを予測して読み込ませて置く必要があります。  リンク先数が少ないページであれば予測もしやすいですが、リンク先が多いページでは予測することは困難になります。また、予測が行なえても、数日後もその予測があっている保証が無く、常にメンテナンスが必要となります。

Predictive Prefetching

 このメンテナンスが難しいprefetch、prerenderをAnalyticsデータと機械学習を使って解決してくれるライブラリがあります。それがguess.jsになります。

Guess.jsをwebpackに導入してみる

ここからは実際にguess.jsをサイトに導入するまでを紹介いたします。

install

npm i guess-webpack --save-dev

webpackへGuessPluginの設定

webpack configで読み込みます

const { GuessPlugin } = require('guess-webpack');

module.exports = (env, argv) => {
    ...

webpackのplugin内にて、GuessPluginを設定します

plugins: [
            new GuessPlugin({
                GA: '自身のView IDを指定してください',  
                debug: true,
            })

 View IDというのは、Google AnalyticsのIDとは違うものです。コチラのリンク先から取得できます。  GuessPluginにはその他にAdvance Optionがあります。詳しくはコチラからご確認ください。  ここでwebpackを動かすとbuild前にブラウザが立ち上がりGoogle AnalyticsにAccess許可が求められます。ここで許可することでGuess.jsがGoogle Analyticsのデータを使用できるようになります。  しかし、build時に毎回この認証が動いてしまうので、production build時にのみ動くように設定を変更してあげるのが良いでしょう。

フロント側の設定

フロント側の設定では、以下のようにguessをimportして実行するだけです。

import {guess} from 'guess-webpack/api';

guess()

しかし、guess()はPredictした候補のオブジェクトを返すだけなので、それからLink Elementを作成するなどの処理が必要となります。サンプルとしては以下のようになります。

import {guess} from 'guess-webpack/api';

window.addEventListener('DOMContentLoaded', () => {
    addPrefetchToHead();
});

function addPrefetchToHead() {
    if (typeof window !== 'undefined') {
        for (const url of Object.keys(guess())) {
            let hint = document.createElement('link');
            hint.rel = 'prefetch';
            hint.href = url;
            hint.as = 'html';
            hint.crossorigin = 'use-credentials';
            document.head.appendChild(hint);
        }
    }
}

その他のサンプル

Guess.jsでは、他にもたくさんのサンプルがありますので是非チェックしてみてください

それでは、良い年末を!

最新の記事