AMP Optimizerを使った新しい表示パフォーマンス改善手段

UI開発者 木村

先日、オランダのアムステルダムでAMP Conf 2018が開催され、AMPに関する最新情報や今後対応予定のプロジェクトなどが発表されました。画面全体を使ったストーリー形式のコンテンツを作成できるAMP StoryやGmailでのAMPサポートなど興味深いテーマが目白押しでした。

私はその中でもAMP Optimizerを使用した、サーバーサイドでのAMP HTML最適化に興味を持ちました。

AMP Optimizerで最適化したページは、AMP Cacheではなくページを公開したサーバー上でも高速化を実現することができます。

AMP HTMLの最適化

AMP HTMLで作成されたページはAMP Cacheにキャッシュされ、そのキャッシュされたページにユーザーを誘導することで、表示速度の高速化を実現しています。AMPページがキャッシュされる時、HTMLソースはそのままキャッシュされるわけではなく、高速化実現のために独自の要素や属性を追加した状態でキャッシュされます。

例として、以前投稿した「AMP HTMLで作るオートコンプリート機能」という記事中のamp-img要素のソースを、オリジナルのURLとキャッシュされたURLで比較してみます。キャッシュされたURLは、Using the Google AMP CacheのサンプルフォームやAMP URL APIを使用して取得できます。

<!-- オリジナルのURL -->
<amp-img layout="responsive" src="https://www.mitsue.co.jp/knowledge/blog/frontend/img/20171208_01.png" alt="" width="377" height="359">

<!-- キャッシュされたURL -->
<amp-img alt class="i-amphtml-layout-responsive i-amphtml-layout-size-defined" height=359 i-amphtml-layout=responsive layout=responsive src=/i/s/www.mitsue.co.jp/knowledge/blog/frontend/img/20171208_01.png srcset="/ii/w390/s/www.mitsue.co.jp/knowledge/blog/frontend/img/20171208_01.png 390w, /ii/w820/s/www.mitsue.co.jp/knowledge/blog/frontend/img/20171208_01.png 820w, /ii/w1200/s/www.mitsue.co.jp/knowledge/blog/frontend/img/20171208_01.png 1200w" width=377><i-amphtml-sizer style=display:block;padding-top:95.2255%;></i-amphtml-sizer>
</amp-img>

キャッシュされたURLのソースでは、i-amphtml-sizer要素やi-amphtml-layout属性などが追加されており、オリジナルのURLのソースと異なっていることがわかります。

AMP Optimizerは、このキャッシュ時に行われるAMP HTMLの最適化を行うことができ、オリジナルのURLでもAMP Cacheに近しい表示速度の向上を図ることができます。

AMP Optimizer

AMP Optimizerはnpmパッケージで公開されており、単純な処理であれば数行のJavaScriptソースで最適化を行うことができます。

今回はAMP Optimizerを使用して次のAMP HTMLソースを最適化し、確認用にHTMLファイルとして書き出してみます。

<!doctype html>
<html lang="ja" amp>
<head>
<meta charset="utf-8">
<script async src="https://cdn.ampproject.org/v0.js"></script>
<title>AMP Optimizer test</title>
<link rel="canonical" href="https://example.com">
<meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1">
<style amp-boilerplate>body{-webkit-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-moz-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-ms-animation:-amp-start 8s steps(1,end) 0s 1 normal both;animation:-amp-start 8s steps(1,end) 0s 1 normal both}@-webkit-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-moz-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-ms-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-o-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}</style><noscript><style amp-boilerplate>body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}</style></noscript>
</head>
<body>
<amp-img src="dummy-image.png" alt="" layout="responsive" width="640" height="400"></amp-img>
<amp-video width="640" height="400" layout="responsive" src="dummy-video.mp4" poster="dummy-poster.png"></amp-video>
</body>
</html>

次のJavaScriptでHTMLファイルからソースを取得し、最適化後にHTMLファイルとして出力します。AMP Optimizerはオプションで、AMPページへのURLや使用するAMPのランタイムバージョンなど指定が可能ですが、今回は特に何も指定せずに変換します。

const inputFilePath = 'before.html'; // 最適化するファイルのパス
const outputFilePath = 'after.html' // 出力するファイルのパス
const ampOptimizer = require('amp-toolbox-optimizer');
const fs = require('fs');
const ampHtml = fs.readFileSync(inputFilePath).toString();

ampOptimizer.transformHtml(ampHtml).then((optimizedHtml) => {
    fs.writeFile(outputFilePath, optimizedHtml);
});

上記のJavaScriptを実行して出力されたHTMLファイルのソースが次です。

<!DOCTYPE html><html lang="ja" i-amphtml-layout="" i-amphtml-no-boilerplate=""><head><style amp-runtime=""></style><link rel="preload" href="https://cdn.ampproject.org/v0.css" as="style"><link rel="stylesheet" href="https://cdn.ampproject.org/v0.css"><meta charset="utf-8"><meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1"><link rel="preload" href="https://cdn.ampproject.org/v0.js" as="script"><script async="" src="https://cdn.ampproject.org/v0.js"></script><title>amp-toolbox-optimizer test</title><link rel="canonical" href="https://example.com"></head>
<body>
<amp-img src="dummy-image.png" alt="" layout="responsive" width="640" height="400" class="i-amphtml-layout-responsive i-amphtml-layout-size-defined" i-amphtml-layout="responsive"><i-amphtml-sizer style="display:block;padding-top:62.5000%;"></i-amphtml-sizer></amp-img>
<amp-video width="640" height="400" layout="responsive" src="dummy-video.mp4" poster="dummy-poster.png" class="i-amphtml-layout-responsive i-amphtml-layout-size-defined" i-amphtml-layout="responsive"><i-amphtml-sizer style="display:block;padding-top:62.5000%;"></i-amphtml-sizer></amp-video>

</body></html>

AMP Cacheと全く同じ最適化をしているわけではありませんが、AMP Cacheと同様にi-amphtml-sizer要素やi-amphtml-layout属性などが追加されています。これにより、オリジナルURLでもAMP Cacheに近しい振る舞いを再現することができ、高速化が実現できます。

AMP OptimizerのGitHubページによると、AMP Projectのページで試した結果、レンダリングの開始までの時間が37%、レンダリングの完了までの時間が42%向上したことが公開されています。

注意が必要な点は、最適化されたページはstyle属性の使用や外部CSSの読み込みなどAMP HTMLのルールに反したソースになるため、AMPページではなく非AMPページとして公開されます。そのため、AMP Optimizerでパフォーマンス改善を行ったサイトで想定される運用パターンは次の二つです。

  • AMP Optimizerで最適化した非AMPページ + 最適化前のAMP HTMLページ
  • AMP Optimizerで最適化した非AMPページのみ

検索結果カルーセルにAMPコンテンツを掲載したい場合は前者のパターンで運用する必要があります。AMP Optimizerで最適化した非AMPページは、AMP HTMLで作られていますがAMPページとして認知されないため、AMP Cacheにキャッシュされず検索結果カルーセルにも掲載されません。逆に検索結果カルーセルへの掲載が不要な場合や、元々サポート外のページの場合は後者のパターンも有効です。

AMP Optimizerを使用することで、オリジナルのURLで高速化が実現できるため、AMPをサポートしている検索エンジンやWebサービス以外から訪問したユーザーに対しても高速なWebページを提供することができ、これまでよりも直帰率の低下や訪問者数の向上などが期待できます。2018年2月現在、npmパッケージでしか公開されていないため動作環境は限られていますが、他の環境でも同様の最適化ができるようになれば、より手軽で効果的にパフォーマンスの改善ができるようになるのではないかと思います。