AMPは高速化のための技術ではないというのは本当なのか？

AMPは高速化のための技術かどうかを問うブログエントリーがありました。

[AMPを「高速化技術」「一瞬で表示する技術」というのはもうやめよう。](https://note.mu/rdlabo/n/nd994c99b5c54)

* WebComponentsを使っているから遅い
* AMPの速さはGoogleの検索結果からプリフェッチするから速いだけである
    * AMPはGoogleのサーバーにコンテンツを乗せるためのプロトコルである

これは僕の理解とは大幅に異なっているので説明します。この説明が正しいとすると、検索結果以外から直接AMPを使ったサイトを閲覧すると「高速ではなくて逆に遅い」ということになります。

さて、これは正しいかどうか。

# HTMLの表示を遅くする要素

高速化の前に、HTMLの表示を遅くする要素についてまとめておきます。

* 再計算
    * 画像のサイズがなくて、読み込んで見てからレイアウトをしなおす
    * スタイルシートを後から読み込んで、要素に適用していく
        * 通常はheadタグ内でdomの解釈前に読み込まれる、linkタグで読み込む時もpriority highで優先的に読み込むので待ちはするものの再計算はしないはずだが、CSS in JSとか後から実行することがありえる
* ブロッキング
    * document.writeでscriptタグを読み込むのが一番重い罪。地獄に落ちる。
* ダウンロード
    * 初期表示に必要のないJSファイルとかもろもろを先に読み込むと、遅くなる
* あとから描画
    * document.readyイベントを受けて、JavaScriptで表示を変更したりして、そこで新しいリソースを読み込むなどすると表示完了がそれだけ遅くなる

なかなかMECEに書きづらい具合に、これらは密接に影響しています。余計なリソースを読み込むことで、ネットワークの帯域を奪ってしまうので、そのぶんブロッキングになったりします。

# AMP

AMPの仕様はこれらの遅くなる要因を注意深く潰すために作られていると思われます。HTMLと比べて記述力が制限されていますが、これによって2つの効果があります。

* 画面表示でブロッキング（白い画面のままロードを待つ）が起きない
    * document.writeができない
    * 初期表示で必要以上のリソースを読み込むことができない
    * メインコンテンツのテキストの表示はまっさきに行われ、画像などはすべて遅延ロード
* 使われるリソースが明確にわかる
    * 必要な画像、JSファイル、CSSなどがHTMLの静的チェックですべて取り出すことができる
        * すべてのアセットがCDN上にキャッシュされていることが保証される
        * プリフェッチしやすくする

特にJavaScriptであとからリソースを追加するというのは実行してみないと分からないことが増えます。どのファイルが必要なのかとか。仕様を制限することでリソースが明確になります。後者は行儀の悪いdocument.writeをする広告対策ですね。広告によりインターネットのエコシステムは維持されていますが、同時によくないHTMLのお作法によりパフォーマンスを下げているということがありましたが、それを制限しようというものです。

前者は明確に「高速化」といっていいでしょう。遅いものをなくすのは高速化ですし。

後者も、CSSを読み込んだらその中でimportしていてさらにネットワークアクセス・・・みたいなことはおきなくなりますし、すべてのアセットをCDN上に置かれていることが保証されます。同一ドメインからすべて読み込めるのであればDNSの解決のコストが減るとかもありますよね。

必要な画像もわかるので、事前に画像をリサイズして端末にふさわしい大きさのものをダウンロードさせることで、通信時間を節約しつつ表示品質も維持するということもamp-imgはやっています。

あとは、AMPのキャッシュを使うのであればJSとかは共通なので読み込みの時間もサイトをまたいで節約できます。まあ、ここは最近、別CDN対応がうたわれているので、おまけですが。

これらの効果などをいろいろ組み合わせることで、レンダリングの高速化と、アセットダウンロードの高速化の両輪で、ユーザーがコンテンツを読み始めるまでの時間が遅くならないようにする==高速な表示を維持するというのがAMPの仕様になっています。AMPは「ネットワークが遅い国でもより良いインターネット体験を提供する」というのがリリース当初に説明された目的です。効果としてはコンテンツ量を1/10になって、速度は4倍になったと説明されています。表示に必要なコンテンツ量が減るので、プリフェッチがなくても高速にはなりますし、プリフェッチしやすい構成になっていてプリフェッチすればさらに高速になるという寸法です。

<blockquote class="twitter-tweet" data-conversation="none"><p lang="ja" dir="ltr">前に試したときにも、GoogleのCDNには載せませんでしたが、べらぼうに速かったですよ。</p>&mdash; hmori (@moridroid) <a href="https://twitter.com/moridroid/status/1184111446096936961?ref_src=twsrc%5Etfw">October 15, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# Googleの検索サイトでの利用以外にプリフェッチの効果が得られない？

現在はprefetchはHTMLで簡単に利用できます。特にAMP的なサイトであれば簡単です。

<!-- https://qiita.com/ShinyaOkazawa/items/f95788c67114d0360e40 -->

自分でポータルページを作り、その中でユーザーが遷移先として有力なページをlinkタグで指定しておけばprefetchが行われます。なので検索エンジン以外でもprefetchは利用できると言えます。prefetchとprerenderがありますが、AMPの場合はJSの解釈が必要なのでprerenderがお手軽で効果が高いでしょう。

```
<link rel="prerender" href="//example.com/future-page.html">
```

遷移先は事前に決めなくても、リンクにマウスオーバーされたときに、JSでlinkタグを追加しちゃうという方法でprerenderやpreloadは実現できます。aタグにrel="prerender"を書くのもウェブのドキュメントではたまに見つかりますが、MDNによると非推奨のようです。

このプリフェッチですが、SPAでは簡単にはいきません。SPAの場合、JSでHistory APIを使ってURLが変更され、RouterがそのURLにマッチしたページ用のコンポーネントにレンダリング処理を依頼することでページ遷移が実現されます。全部のリロードが行われないため、高速に遷移ができるというのがウリでしたよね？しかし、大抵のSPAでは最初のレンダリング時にAPIアクセスを行ってJSONを読み込む必要がありますが、キャッシュ可能なコンテンツでないとダメです。APIのGETアクセスをキャッシュ可能にするかどうかというと、必ずしもキャッシュする実装にはしないと思いますし、遷移先ごとに必要なAPIを全部列挙してプリフェッチ可能にするのはかなりおおごとです。

Next.jsにはLinkタグにプリフェッチ機能があったりしますが、Next.jsの場合も、ページごとにわかれているJavaScriptファイルの先読みだけを行う実装になっています。AMPで簡単に実現できるprefetchと比べると事前取得できる要素が少なく、効果も限定的です。

# WebComponentsと速度の問題

WebComponentsが遅くなる、という問題についてはどうでしょうか？amp-imgの話と想定して進めます。amp-img以外のタグについては後述します。WebComponentsは独自のタグを作る仕組みです。タグの表示は、JSが読み込まれないと表示されません。サーバーサイドレンダリングが必要、みたいに言われている話と同じですね。

では、読み込まれないと表示されないので困るかというと、それは少し違います。AMPが対象としているサイト（かつ検索結果から直接飛ぶ可能性が高いもの）には、ニュースやブログなどのテキストを含むサイトがあります。テキストが表示されれれば、Content Meaningful Paintは達成します。画像などの他の要素はテキストが表示されたあとに表示されるのでも問題はありません。

amp-imgを使わずにimgタグを使えばそもそもJSの実行が入らないので高速じゃないか、というのはもっともな意見ですが、ここにもトレードオフがあります。最新のChromeではimgタグそのものにsrcsetもloadingによる遅延ロードもありますので、これを使えばamp-imgよりもJSの処理時間分高速と言えます。

しかし、IE（まだサービスによっては無視できない）を切り捨てなければsrcsetは利用できませんし、最新のChromeでしかloadingはありません。トロッコ問題で、一部のユーザーを切り捨てれば残りのユーザーはもっと高速、という感じですね。で、AMPは大多数のユーザーを現在は選択しているということになります。IEユーザーを選んだというか、AMPリリース直後はSafariもFirefoxまだギリギリサポートしたばかり、っぽい感じだったので、そういう意味ではAMPの選択は悪くはなかったと思います。srcsetとloadingが全部のブラウザに普及したらimgタグで、となる気がします。

改善の方向性としては、最高速度は変わらないものの、全区間の1/3しか270km/hの速度が出せなかった700系新幹線に対して、全区間の2/3の領域で2/3で270km/hの速度を出せるようにして東京ー大阪間の時間を短縮したN700系新幹線みたいな感じじゃないですかね。そのための手段がWebComponentsであったと。コーナーが少なければ全車両動力車の新幹線じゃなくて、先頭だけ動力車のTGVの方が効率が良いけど、コーナーが多い日本では新幹線が適していた、というのと同じ感じですね。

# 高速化とはなんなのか

Closure Compilerを使うとJavaScriptのコードを最適化して高速にしてくれます。もちろん、その手法は自分で書いても同じ効果が得られます。じゃあClosure Compilerは高速化じゃないのか、というと高速化ですよね？

WebAssemblyはネイティブコードの半分程度の速度で動作し、JavaScriptそのものよりも高速なのでWebAssemblyの導入を考えるにあたって高速化を期待する人は多いでしょう。ただし、常に高速になるとは限りません。wasmのダウンロードと解釈のトレードオフがあります。場合によっては遅く場合もあるが、ワークロードの種別によって得られる結果が良ければ「高速化」を目的として導入されるでしょう。

RubyやPythonと比べると、Goを導入するのは起動時間の短縮化などのメリットを期待して導入します。これは高速化です。しかし、Goが最速かというと、CPUヘビーな処理ではC++やRustに比べると一段劣ります。

まとめると、何かしらの作業の工数をかけたら、必ずしも100%とは限らないものの、時間短縮の可能性があるのであれば高速化といってしまってもいいと思います。特定のケースで「もっと高速な手法」があったとしても、それは高速化であることには代わりはありません。

高速化は効果だけではなくて、かける工数や選択の狭さとかも考慮して作戦を立てる必要があります。トレードオフのところで紹介したように、イオラ（amp-img）は範囲は広いけど、メラミ（imgタグ直書き）の方がダメージがでかい、みたいな。最終的にどちらが効果的かは対象としているサービスのユーザー層次第です。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">世の中にはいろいろな技術があるし、個別のケースに対して100%正解の方法というのは個々にあるとはおもうけど、60%の労力で90%満足できるようにするためのものというのも道具として重要で、そういう意味でGoとかAMPとかは自分の感覚としては後者。</p>&mdash; Yoshi Yamaguchi 🇯🇵 (@ymotongpoo) <a href="https://twitter.com/ymotongpoo/status/1183933481375518720?ref_src=twsrc%5Etfw">October 15, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# 高速化以外のAMPの持つポテンシャル

AMPは当初モバイルの高速化のためのもの、という説明がされてきましたが（当初はAccelerated Mobile Pagesだったが、今年AMPが正式名称となった）、それだけではもったいないぐらい、当初と比べて機能が増えています。検索エンジンとの親和性の高いニュース系サイト以外に、でかでかと画像をいっぱい貼ったようなサイト用のコンポーネントもあり、実際、 https://bmw.com とかLINE@とかで使っているとのこと。

bmw.com はソースを読んだのですが、モバイル向けではないデスクトップブラウザにもレスポンシブに対応するサイトになっていますし、メインコンテンツもAMPのコンポーネントをそのまま使っています。おそらくSSRした結果をそのまま載せているんじゃないかと思います。v0.jsとかも自分のホスト上で提供していたりします。高速化のための制限された記法であっても、HTMLとしてvalidなままなので、そのまま使うことができます。AMP validではない書き方（``<link rel="amphtml">``とか``<link rel="canonical">``がない）にあえてして、キャッシュに載せない前提で部品だけ利用することも可能です。

AMPは当初は使えなかったフォームとかselectとかも追加されていますし、各種ウェブサービス、とくに動画系のプレイヤーなどが充実しています。ざっと見ると、日本のサービスのコンポーネントが全然無いですね。ホットペッパーとかRettyとか食べログみたいなサイト、ニコニコ動画、note.muとかのコンテンツ系サービス、クックパッドのレシピとかそういうのもあると面白い気がします。

AMPはGoogle向けのもので、Googleのサービスと一緒に使うのでなければ意味無いのでは？みたいなよくあるFAQのブログエントリーもありました。

https://blog.amp.dev/2019/05/23/debunking-common-amp-myths/

もちろん、タグを使いまくれば、その分遅くなりますよ。

# 改めてAMPの価値を考える

AMPはさまざまな技術の集合であって、AMPと似た仕組みを他の会社が作ることも可能です。文法とかタグとかは独自でしょうが、ニュースを各社からあつめて配信するサイトで似たようなことをしていると聞いたことがあります。AMPはそれをオープンソースでやっているものです。AMPのように全部のブラウザをターゲットにしなければ、各社のサービスに特化してもっとチューニングする（SafariとChromeのウェブビューのみに特化して機能を使い尽くす）方向で、AMPよりも速度を出すこともできるでしょう。

Google検索対応がなければ関係ない、という意見もありますが、CloudFlareは対応しているようですし、bingとかバイドゥとかの検索エンジンも対応しているとのこと。

AMP用サイトだけではなく、本体のサイトもAMPで作って本体ごと全部CDNに載せる例（ https://bmw.com ）も紹介しました。AMPで行なっている高速化技法とか、トレードオフは、実現可能性を考えると、専業のメンバーを抱える会社ががんばってなんとかやりきれるレベルをそこそこのコストで実現できる感じでうまくまとまっているので、悪くないと思います。AMPはGoogle専用のものだから（という誤解）というコメントが元エントリーの方にはついていましたが、AMPはひとつのソリューションとして、バラして学ぶには良い題材です。

個人的にはVueもAngularもReactも一通りやってみて、そろそろ新しいことがやってみたいなと思っていたところなので、bmw.com的な本体側でAMPのコンポーネントを利用するサイトを作ってみようかな、と思っているところです。

# NEXT Conan's Hint

で、元のエントリーは「検索エンジンとの親和性」をAMPのメリットとしていますが、そこに関して、逆にAMPで速度以外にマイナスになる闇についてのReal Worldな生々しいHTTPの話は @yosuke_furukawa がきっと別のエントリーを書いてくれるでしょう。僕個人はメリットの方が強いと感じていますが、手放しで100%良いというものではなく（元のエントリーで説明されているのとは別の理由で）、そこのトレードオフも考慮に入れた上でAMPをそのまま使うか、AMPの構成技術を学ぶ題材として使うか、あるいは使わないかを決めれば良いかと思います。