Google に Cache された AMP ページの遷移先は、通常ページとなり、AMP の速度の恩恵を受けられるのは、何もしなければ基本的に初回表示時のみとなります。
AMP URL API で AMP ページのリンクを取得する方法もありますが、このブログでは何故か AMP URL API が上手く動作せず、放置しておりました。

その後、2018 年の AMP Roadshow で 紹介されていた Amp Optimizer の存在を思い出し、これを使えば同じようなことが実現できそうに思いましたので、試しに使ってみました。
実施したことを記載します。


AMP Optimizer とは何か?

AMP HTML を元に、最適化した HTML を作成するツールです。
自前のサーバー上で、Google の Cache サーバーに配置された AMP HTML 並みのパフォーマンスを出すことができます。
amp-toolbox/packages/optimizer at master · ampproject/amp-toolbox Why is it faster?節には以下のように記載されています。

Why is it faster?

In order to avoid Flash of Unstyled Content (FOUC) and reflows resulting from to the usage of web-components, AMP requires websites to add the amp-boilerplate in the header.

なぜそれが速いのですか?

FOUC(Flash of Unstyled Content)や Web コンポーネントの使用に起因するリフローを回避するために、AMP ではヘッダーに amp-boilerplate を追加することを Web サイトに要求しています。

The amp-boilerplate renders the page invisible by changing it’s opacity, while the fonts and the AMP Runtime load. Once the AMP runtime is loaded, it is able to correctly set the sizes of the custom elements and once that happens, the runtimes makes the page visible again.

amp-boilerplate は、フォントと AMP ランタイムがロードするまで間、HTML要素の透明度 を変更するこで ページを非表示にします。 AMP ランタイムがロードされると、カスタム要素のサイズを正しく設定でき、設定が完了すると、ページを再び表示します。

As a consequence, the first render of the page doesn’t happen until the AMP Runtime is loaded.

結果、ページの最初のレンダリングは AMP ランタイムがロードされるまで行われません。

To improve this, AMP server-side rendering applies the same rules as the AMP Runtime on the server. This ensures that the reflow will not happen and the AMP boilerplate is no longer needed. The first render no longer depends on the AMP Runtime being loaded, which improves load times.

これを改善するために、AMP サーバーサイドレンダリングはサーバー上の AMPランタイム と同じルールを適用します。 これにより、リフローが発生せず、AMP ボイラープレートが不要になります。 最初のレンダリングはロードされる AMP ランタイムに依存しなくなり、ロード時間が改善されました。

通常の AMP での記載の場合、AMP ランライムの読み込みまでの間、処理都合上、画面を非表示にしていますが、AMP Optimizer を使った HTMLの場合、非表示にする処理が不要になるので早くなると理解しました。


前提

当ブログは、Python Mezzanine で構築しています。
このため、後述するサーバー側の設定として、Django に関する記載があります。

  • PythonのVersion

    python -V
    Python 3.6.7    
    

  • Django のVersion

    pip list | grep Django
    Django                     1.11.20  
    

  • Mezzanine のVersion

    pip list | grep Mezzanine
    Mezzanine                  4.3.1    
    


Blog で AMP Optimizer で 最適化した HTML を表示するために実施したこと

処理の全体像

AMP page dispatch.png - Google ドライブ

処理の流れ

処理の流れは以下の通りです。

  1. AMP ページの ページリンクURLを調整しておく。

  2. kemsakurai/amp-optimized-page-generator: Amp optimized page generator for https://www.monotalk.xyz で、日次で、AMP ページをスクレイピング、取得した HTMLをインプットに、最適化したHTMLを生成する。

  3. ユーザーが AMP Cache にアクセスし、リンクをクリックすると、urls.py で URLが調整したページリンクかどうかを判断、調整したページリンクであれば、最適化したページを表示する。

  4. urls.py で URLが調整したページリンクではない場合、つまり通常のWebページからのリンクの場合は、通常ページを表示する。

実施したこと

以下、処理の流れに沿って、実施したことを説明します。

1. AMP ページの ページリンクURLの調整

filter を作成、作成したフィルタを、DJango テンプレート内でえ呼び出し、サイト内遷移時の URL を変更しました。

  • 作成したフィルター

    @register.filter
    def append_amp_optimized_param(url):
        url_parts = list(urlparse.urlparse(url))
        url_parts[2] = "/ampoptimized" + url_parts[2]
        return urlparse.urlunparse(url_parts)
    

  • Djangテンプレートの修正箇所

    <li><a href="{{ post.get_absolute_url|append_amp_optimized_param }}">{{ post.title }}</a></li>
    

2. amp-optimized-page-generator で、日次で AMP ページをスクレイピング、取得した HTML をインプットに、最適化した HTML を生成する。

Node.js で、AMP ページをスクレイピングして、取得したHTML をインプットに、最適化した HTMLを生成するツールを作成しました。
kemsakurai/amp-optimized-page-generator: Amp optimized page generator for https://www.monotalk.xyz

ツールは以下2つに分かれます。

  • ampUrlFinder.js
    Sitemap.xml に記載されているページから、AMP HTML の URLを取得し、通常ページ URLと、AMP HTML のURLの関係を示す JSONファイルを生成します。

  • htmlGenerator.js
    ampUrlFinder.js生成したJSONファイルを元に、最適化したHTMLファイルを生成します。

ツールが参照するサイトマップは、config.js変更できます。

  • config.js
    module.exports = {
        siteMapUrl : 'https://www.monotalk.xyz/sitemap.xml',
        domainUrl : 'https://www.monotalk.xyz'
    };
    

ツール実行には以下のようなスクリプトを作成し、crontab で 日次で実行するようにしました。

  • gen_amp_optimized_page.sh
    #!/bin/sh
    PROJECT_HOME="/var/xxxxx/"
    # run npm task
    cd /root/script/amp-optimized-page-generator    
    npm run find-amp-url
    npm run gen-html
    
    # cp gen htmls
    # django のテンプレートディレクトリに生成したhtmlをコピーする    
    rm -Rf "$PROJECT_HOME"amp_start_blog_post/templates/amp_start_blog_post/htmls
    \cp -Rf htmls "$PROJECT_HOME"amp_start_blog_post/templates/amp_start_blog_post/htmls
    
    ####################################
    # clear cache
    BLOG_ROOT="var/xxxxx/"
    cd $BLOG_ROOT
    python3.6 manage.py clear_cache
    
    ###################################################
    # RESTART httpd
    /bin/systemctl restart httpd.service
    

3. urls.py での ディスパッチ設定と、View の作成

3. ユーザーが<wbr> AMP Cache に<wbr>アクセスし、<wbr>リンクを<wbr>クリックすると、<wbr>urls.py で<wbr> URLが<wbr>調整した<wbr>ページリンクか<wbr>どうかを<wbr>判断、<wbr>調整した<wbr>ページリンクであれば、<wbr>最適化した<wbr>ページを<wbr>表示する。<wbr>と、4. urls.py で<wbr> URLが<wbr>調整した<wbr>ページリンクではない<wbr>場合、<wbr>つまり<wbr>通常の<wbr>Webページからの<wbr>リンクの<wbr>場合は、<wbr>通常ページを<wbr>表示する。<wbr>実現するために urls.py のディスパッチ設定と、新規でHTML ファイルを読み込むためのView を作成しました。

  • urls.py

    urlpatterns += [
        ...
        # add amp_start_blog_post
        url("^ampoptimized/", OptimizedAmpView.as_view()),
    ]
    

  • views.py

    from django.views import View
    from django.shortcuts import render
    from django.conf import settings as django_settings
    import urllib.parse    
    
    class OptimizedAmpView(View):
        def get(self, request, *args, **kwargs):
            base_url =  urllib.parse.quote(request.path)
            elems = base_url.split("/")
    
            file_name = elems[len(elems) -2][:100] + ".html"
            return render(request, 'amp_start_blog_post/htmls/' + file_name)
    
    OptimizedAmpView作りが適用で、上記でファイルがない場合は、500エラーが発生します。
    ファイルが内場合は、404エラーとハンドリングしたほうが良いかと思います。
    ファイルがなければ、404エラーを返す。render だと、テンプレートとして評価されるので、直接ファイルを取得するように変更しました。
    from django.views import View
    from django.http import HttpResponse
    from django.http import Http404
    import urllib.parse
    from pathlib import Path
    
    class OptimizedAmpView(View):
        def get(self, request, *args, **kwargs):
            base_url =  urllib.parse.quote(request.path)
            elems = base_url.split("/")
            file_name = elems[len(elems) -2][:100] + ".html"
            response = HttpResponse(content_type="text/html")
            directory = str(Path(__file__).resolve().parents[1])
            try:
                for line in open(directory + '/amp_start_blog_post/templates/amp_start_blog_post/htmls/' + file_name):
                    response.write(line)
            except FileNotFoundError:
                raise Http404("Page does not exist")
            return response            
    


Page Speed Insights の結果、適用して思ったこと

最適化したページのPage Speed Insights の結果 と、適用して思ったことを記載します。

Page Speed Insights の結果

以下は、Mobile のスコアです。
2019-05-26 11.54.42.png - Google ドライブ
以下は、PC のスコアです。
2019-05-26 11.54.57.png - Google ドライブ

通常のHTMLの Mobile スコアが以下なので、50点近く上昇しています。
2019-05-26 12.13.48.png - Google ドライブ
何より体感でも速くなったことがわかります。

適用して思ったこと

適用した結果思ったことを記載します。

  • 自動広告が表示されない
    これは、通常のAMPページでも最近出てきていない気がしますが、自動広告が表示されません。
    広告タグを埋める場合は、通常HTMLの広告タグを設定しないと表示されないのかもしれません。

  • 通常のHTMLを差し込んでもいいかもしれない
    試してないですが、OptimizeしたHTMLにそれだけでは表現として足りない部分に通常 HTML を差し込んでも良いかもしれません。

  • Google Analytics には元の HTML に GTM タグを設定をしていると記録された
    GTM は AMP と 通常ページでタグの差し替えが必要に思いましたが、サーバー上で表示してみると、AMP ページと同様に記録されました。


参考

以下、参考にした記事になります。

広告は表示させておきたいので、その辺りをもう少し気が向いたら調べてみようかと思います。
以上です。

コメント