天然パーマです。

AMPで速くする。AMPを速くする

いくつかの Web ページを AMP 化した。何をもってして「速い」と判断するかは後述するとしてとにかく速くなった。そしてさらに 3 つのテクニックを使って AMP ページを高速化した。今回はその過程を紹介する。

AMP だと何が速いか?どうして速いか?

最初に、何をもってして速いと言うのかを考えないといけない。まとめると以下の 3 つになった。

  1. ページの表示が速い
  2. Core Web Vitals を向上させる
  3. Google 検索結果からの遷移が速い

それぞれについて見ていこう。また、AMP だとどうして速いかも考える。

1. ページの表示が速い

ページの表示が速いというのはページのダウンロードが速くなる、描画が速くなるといったことである。これは分かりやすい。

amp.dev ではAMP が速い理由として以下を上げている。

  • すべての AMP JavaScript を非同期に実行
  • すべてのリソースを静的にサイズ設定
  • 拡張機能メカニズムによるレンダリングのブロックを阻止
  • すべてのサードパーティ JavaScript をクリティカルパスから除外
  • すべての CSS のインライン表示とサイズ制限を義務化
  • フォントの呼び出しを効率化
  • スタイルの再計算を最小限に抑制
  • GPU で高速化されたアニメーションのみを実行
  • リソースの読み込みを優先
  • 瞬時にページを読み込み

まあこれだけやれば、よほど最適化しているページじゃなければ、速くなる。そのためののフレームワークが AMP といえる。

また、Valid な AMP ページにするためには、上記を満たすために AMP のルールに準拠する必要がある。例えばいくつかのタグが禁止されている。script タグもそうだ。一部のタグは img なら amp-img を、iframe なら amp-iframe と代替が用意されているが、それぞれ widthheight が必須だったりとより「厳格に」書かなくてはいけない。on で始まる onclickonmouseover などの属性も禁止されている。CSS はインラインで書かなくてはいけない。現在のところサイズは 50KB 以下でなくてはならない。広告は貼れるが、対応しているプロバイダは限られている。

既存のページを Valid な AMP にするのであれば、こうした「無駄なことを省く」ための制限をクリアしなくてはいけない。すると、結果的に機能を削ることになる。極端な例だが「派手な JavaScript でのアニメーションを静止画にしましょうね」とかそういうのである。この場合、 AMP が速いのではなく、AMP 化することで機能を削るから速くなる とも言えだろう。

2. Core Web Vitals を向上させる

「2」の Core Web Vitals の件。Core Web Vitals では 3 つの指標を掲げている。

  • LCP - ページの表示速度
  • FID - ページの反応速度
  • CLS - レイアウトの安定性

高速化を「大きく捉えれば」 CLS なんてのもその一つである。レイアウトシフトが起こるとフラストレーションがたまりユーザーは(本来の意味ではないが)「遅いサイト」と印を押すかもしれない。例えば、上記の「すべてのリソースを静的にサイズ設定」なんてのは描画が速くなると同時に、 CLS を起こさないための工夫である。実際問題、amp-img タグには width と height を明示しなくてはいけない。

そして、Google は AMP が Core Web Vitals を向上させると述べている。

AMP は、ユーザー ファーストなサイトの開発を可能にするために作成されました。また、AMP は、サイト運営者が優れたページ エクスペリエンスを実現できる、コスト効果の高いシンプルなソリューションです。

https://developers-jp.googleblog.com/2020/12/amp.html

Core Web Vitals の向上が広い意味でも高速化につながるといえる。

3. Google 検索結果からの遷移が速い

最後に「3. Google 検索結果からの遷移が速い」である。これは AMP 化すると Google の AMP キャッシュにのったページを返すから、なのであるが、もう少し詳しく見てみたい。

実は Google の AMP キャッシュの CDN はさほど速くない。手元で集計してみると、TTFB が「200ms〜300ms」であった。これよりもっと速い CDN はあるし、近場のサーバーへのアクセスならば「x0ms 台」が出る。

なので、CDN が速いわけではない。

速いのは Google 検索結果が表示されるタイミングでブラウザがページを prefetch もしくは「先読み」しているからである。

Signed Exchange=SXG に対応させているページは AMP に関わらず であるが、検索結果の時点で prefetch されているので、リンクをクリック/タップしてからの表示が数 ms 台と非常に速い。また、SXG させてない AMP ページ でも検索結果でリンクが表示域に入った瞬間にページが先読みされる。少なからず検索上位のページはそうだ。Safari は SXG や prefetch に対応していないが、この恩恵を受けることができる。

以下は AMP 化/SXG 対応させた本ブログが Google 検索結果に出てる様子である。Priority が「Lowest」になって対象ページを prefetch している。

loading...

これは SXG の例であるが、SXG 対応してなくとも AMP であれば先読みされることがある。AMP 化させることは Google 検索結果からの遷移を高速化することになるのである。

AMP 化して速くする

さてページを AMP 化してみよう。いくつかのサイトで試した。例えばこのブログもそうである。このブログは広告もないし、重要な JavaScript もないので簡単だった。

  1. 一からテンプレートをおこしてみる
  2. AMP ランタイムの JS を読み込む
  3. CSS をインライン化、!important は使わない
  4. img タグを amp-img にして width height を明示する。分からない場合が多いので、その辺は工夫した。加えて iframe も同様に amp-iframe にした
  5. SNS ボタンで使ってた無駄な JS を省く。画像と URL リンクだけでシェアできるようにする
  6. embedly の AMP コンポーネントを使うようにした。よく使われているサービスには AMP コンポーネントがあることが多い(この記事なんかは画像を width/height 指定せずに embedly で貼っているので、CLS が発生してあまりよくない…)
  7. AMP Validator に通して確認

といった具合である。

実際問題、 このページは速い と思う。

ただ、サイトによってはそもそも DOM の数を減らしたりや CSS を削ったり、広告を廃止したり、AMP コンポーネントではサポートしてないスクリプトを削除するなりとサイトの作りそのものを変更しなくてはいけない場合があるだろう。

AMP をさらに速くする

AMP 化したページをさらに速くするテクニックがある。以下の 3 つである。後ろの 2 つは AMP に限ったものではない

  1. Optimize する
  2. Service Worker を導入する
  3. Signed Exchange に対応させる

1. Optimize する

amp.dev では「ホストされた AMP ページの最適化」としていくつかのテクニックが紹介されている。「ホストされた」とは Google などの AMP キャッシュではなく、自前のオリジンサーバーで配信している AMP ページという意味である。

この記事によると <head> タグ内の <meta><link><script> などの書く順番を最適化したり、ヒーロー画像といって、ページの描画にとって大切な画像を preload させるといいとのことだ。

そして記事の後半にはこう書かれている

AMP オプティマイザを使おう

と。で、AMP Optimizer ってなんぞって調べたんだけど、上記のテクニックを含めて通常の AMP ページをさらに高速化させるためのプログラムである。node や Go、PHP 実装がある。そこで行われていることを知れば、AMP をさらに速くするためのテクニックが分かる。以下の通りだった。

  1. Boilerplate をやめる
  2. ランタイムの CSS をインラインで読み込む
  3. ヒーロー画像を preload する
  4. head 内の要素の順番を最適化する
  5. Server Side Rendering する
  6. minify
  7. その他 Resource Hints

「1」と「2」と「5」がキモである。この場合の Server Side Rendering ってのは AMP の Boilerplate が行うレイアウトの計算を予めサーバーサイドで行うことである。それによって Boilerplate が必要なくなるので、描画前に一瞬挿入される白画面がなくなる。

Core Web Vitals の指標である Lighthouse の点数も上がることを確認している。

loading...

2. Service Worker を導入する

PWA のひとつ、Service Worker を導入する。これは AMP に限ったことではない。

が、AMP なら簡単に導入できる。amp-install-serviceworker コンポーネントを使うのだ。以下のページが詳しい。

Service Worker を使えば、画像などのアセットもそうだし、AMP ランタイムのスクリプトもキャッシュしてくれる。

loading...

サイト内を巡回するときにすでにリソースがキャッシュされているので、速くなる。

3. Signed Exchange に対応させる

これも AMP に限ったことではない。

何ができるかと言うと、Google などの AMP キャッシュのページを Google のドメイン URL ではなく、オリジンの URL で表示できるというものだ。

Cloudflare だと簡単に Signed Exchange に対応させることができるのでやってみたら、本当に簡単だった。AMP Real URL という機能だ。

loading...

というわけで本ブログも Signed Exchange = SXG に対応したので、Chrome だと以下の挙動を見せる。

  1. Google で「yusukebe」と検索する
  2. 検索結果にこのブログが表示されることになるので、このブログのトップページが prefetch される
  3. リンクをクリックするとドメインは yusukebe.com になって prefetch していたページを返す

面白い。Safari を含め iOS で挙動するブラウザで SXG に対応したものが無いのが残念である。

ちなみに、上記した通りこのブログは現在、Cloudflare を使って配信されている。Pages という機能でエッジ上にて Hugo を実行し、生成されたページを CDN に乗せている。これも AMP に限った話ではないが、CDN に乗せれば速くなる。

やってみた

で、実際に既存のページ(本ブログではない)を AMP 化して、さらに高速化した時のログがあったので、それをベロっと貼り付けておく。ちなみに配布されている Optimizer を使っていない。


  • Chrome に AMP Validator 拡張を入れる
  • ついでに CWV 測れるやつも入れる
  • JS をやめる
    • prettydate などをサーバーサイドでレンダリングする
  • !important が使えない
  • www.google-analytics.com に prefetch してたのを消す
  • fallback 画像を設定
  • iframe にも fallback 画像を設定することでファースト view に入ってなくても使える
  • 無駄な CSS の font-family を消す
  • <style amp-custom> 内に CSS を全て書く。テンプレートを利用して別ファイルで管理、include させた
  • CSS はなるべく minify する
    • のちに HTML も minify した
  • Cookie 使う動的ページを使わないようにする
  • CSS の編集は pretty(minify しない)で行い、あとで minify する
  • デバグ用に ?amp=1 で強制的に AMP ページを表示するようにした
  • v0.js などを preload する
    • <link rel="preload" as="script" href="​​https://cdn.ampproject.org/v0.js">
  • boilerplate をなくす
  • runtime の CSS をインラインに書く
  • Optimizer 通したこと示す
    • <html amp i-amphtml-layout i-amphtml-no-boilerplate transformed="self;v=1">
  • AMP レイアウトを Sever Side Renering する
    • といっても amp-img に data-hero 属性がある場合のみ
    • amp-img の内側に img タグが入る、preload される
    • <img class="i-amphtml-fill-content i-amphtml-replaced-content" decoding="async" alt="<%= $title %>" src="<%= $thumbnail_url %>">
    • amp-img の中に i-amphtml-ssr 属性を追加する
  • head タグの中のタグの順番を優先度に合わせて並べ替える
  • インライン CSS でも使ってなるべく CLS 起こさないようにする
  • PWA の Service Worker を入れる
    • 1 時間あれば入る
  • amp-install-serviceworker を使う
    • manifest.json
    • sw.js
    • install-sw.html
    • これらを静的に配信するようにする
  • 他にも theme-color apple-touch-icon など本体の HTML ヘッダに追加すべきことがある
  • <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"> と viewport の幅を縛らないとエラー出る
  • AMP の計測は PSI や Lighthouse の Performance よりも AMP Page Experience Guide のアドバイスを参考にする
  • PSI や Lighthouse の Performance の得点、アドバイスでは v0.js で怒られるが、AMP Page Experience Guide なら怒られない = v0.js を考慮して空気読んでくれてる
  • 点数じゃなくて、(フィールドデータの)LCP、TBT、CLS が緑ならばよい
  • ServiceWorker を使えば v0.js 等をキャッシュしてくれる
    • その他画像などアセットもキャッシュ
    • モバイル回線だと体感で分かるほど爆速になる

以上だ。

その他

他にも AMP に関しては、Web Components フレームワークとして広く普及してて使いやすいものであるということを付け加えたい。特に AMP キャッシュに乗せる必要がなければ Valid な AMP ページにせずに、部分的に AMP コンポーネントを使う、なんてことをしてもよい。bmw.com では Valid な AMP ページを用意しつつ、canonical で指定している Non-AMP なページでも AMP コンポーネントを使っているのを確認している。

AMP に限った話ではないのは SXG も同じだ。Non-AMP なページでも SXG を使う利点はある。

まとめ

  • AMP だと何が速いか?
  • どうして速いか?
  • AMP 化する
  • AMP をさらに速くする

について実際の経験を踏まえて紹介してきた。よいことずくめみたいに書いたがそうじゃない面もあるはずだ。自分のサイトを AMP 化するのに大きな工数がかかるかもしれない。Google の AMP ビューアーをうざいと思っているユーザーもいる。他にもたぶんたくさんある。

ただ分かったことは、AMP は優れたフレームワークであるという点だ。導入せずとも参考になることはたくさんある。検討してもいいだろう。