とろろこんぶろぐ

かけだしR&Dフロントエンジニアの小言

Gatsby.js で AMP 化するときの注意点

Gatsby.js

React.js + GraphQL ベースで簡単に静的サイトが作れるフレームワークWordPress よりも軽量で柔軟で開発者初心者でも扱いやすく、 markdown を書くだけでオリジナルのブログが簡単に作れるため流行ってきています。

www.gatsbyjs.org

実際に使ってみると確かにほとんど自分でコードを書かなくてもサンプルは揃っているし、 デザインテンプレートも充実しているのですぐにブログを公開することができます。

しかし markdown で書く場合は、 markdown to html が自動的に行われてしまうので、 実際のブログ記事本文に対して CSS をあてることに苦労します。 例えば、ブログの記事ごとに内部のリンクや太字に細かい修正を与えたくても、 基本的にはクラスやIDを振れるわけではないので、細かなスタイリングはできません。 もちろん CSS を global に与えることはできるので、全体として統一感のあるスタイルは自分で定義できます。

gatsby-config.js にいろいろプラグインを足していけば自分で意識することなくいろんなことができます。 例えば、静的ファイルの配信や画像の加工と最適化(←これ結構すごい)、サイトマップ生成やPWA化までできます。

TypeScript も苦労なく取り入れられるので開発者にとってもありがたいです。 Netlifyなどと連携すれば思い立ってからデプロイまで高速にできるのでありがたいフレームワークになっています。

AMP

AMP はブログのような記事を公開する静的サイトと相性がよく、 Google が検索結果の SERP を優遇することがあるため SEO 的にも有利とされており、 WordPress などでもよく取り入れられることがあります。

Gatsby でも使いたくなる人が結構いそうで、 GitHub 上でも Gatsby での AMP 化について以下に詳しく議論されています。

Consider adding first-class support for AMP · Issue #13454 · gatsbyjs/gatsby · GitHub

しかし現時点で具体的に AMP 化を Gatsby 本体でサポートするには至っていません。

そのため AMP 化する一番簡単な方法は、 html2amp というツールを使った plugin を使うことだと思います。 html2amp は HTML のタグを適切にAMP用のタグに変更して AMP HTML を吐き出してくれるツールです。 例えば img タグを amp-img タグにするといった簡易的な変換ツールといった感じです。

gatsby-plugin-html2amp | GatsbyJS

GitHub - tomoyukikashiro/html2amp: html2amp is simple converter from HTML into AMP(Accelerated Mobile Pages).

これを使えば gatsby build 時に AMP 化した HTML を同時に生成することができます。 このプラグインの場合、 gatsby develop では AMP 化したものを確認できないので注意が必要です。

また内部で画像サイズなどを取得して最適化してくれようとするので、 過去の記事の画像が存在しない 404 になってしまうと html2amp が落ちてビルドに失敗します。 同様に何らかの原因で html2amp が落ちてしまうと build そのものに失敗してしまうので、 gatsby develop で確認し CI上ではじめて build が走るようにしているとデプロイできないことになるので注意が必要です。

基本的に AMP バリデータを自分でかけながら確認しているわけではないので、 デプロイしてから AMP のルールに基づいてなかったということに気付いたり、 画像が思ったように表示されてなかったりということに気付いたりします。

html2amp は files: ["**/index.html", "index.html"], とオプションで指定するとすべての記事を AMP 化しようとするので、 もし AMP 化を試みる場合は意識しながら記事やReactテンプレートを書く必要があるかなと思います。

ただ serviceWorker や optimizer もオプショナルに利用できるようになっており、 細かなニーズに応えてくれている OSS なので、今後より使い勝手のイイものになってくれるといいなと思います。

Web story (AMP story)が使えない

Web ストーリー(元AMPストーリー)は、AMP が提供している最もリッチなコンポーネントです。 AMPストーリーは instagram などで最近よくみる全画面でスライドショー的に画像や動画が順に表示されるコンテンツです。

これを取り入れようとしても Gatsby.js では Web ストーリーを利用できません。 テンプレートとして新たにAMPストーリー用のページを作る場合は、 AMP のスクリプトを react-helmet 経由で head タグに差込み、 以下のように amp-story を直接書いたとします。

return (
  <>
      <amp-story
        standalone
        title="Joy of Pets"
        publisher="AMP tutorials"
        publisher-logo-src="/salty_egg.jpg"
        poster-portrait-src="/salty_egg.jpg"
      >
        <amp-story-page id="cover">
          <amp-story-grid-layer template="fill">
            <amp-img
              src="/salty_egg.jpg"
              width="720"
              height="1280"
              layout="responsive"
            ></amp-img>
          </amp-story-grid-layer>
        </amp-story-page>
      </amp-story>
   </>
)

しかし実際に実行してアクセスしてみても以下のようなエラーを出して表示されません。

index.js:2177 Render timeout waiting for service amp-story-render to be ready.<200b><200b><200b>
...
log.js:710 Uncaught Error: Render timeout waiting for service amp-story-render to be ready.<200b><200b><200b>
    at cb (log.js:710)
    at Za.f.createError (log.js:359)
    at timer-impl.js:142
    at timer-impl.js:83

AMP のエラーは深堀りしてませんが、まともに議論されていなさそうです。 面倒なので大してこれ以上調べてません。

Render timeouts waiting for service to load · Issue #6569 · ampproject/amphtml · GitHub

Uncaught Error: Render timeout waiting for service amp-story-render to be ready.​​​ · Issue #22774 · ampproject/amphtml · GitHub

Web story は body 直下に置くことを前提に作られているコンポーネントです。 逆にいうと amp-story しか置けないようになっています(AMP validator でもひっかかる)。 おそらくそれが原因で上記エラーになってしまったのかなと予想しています。

Gatsby は body 直下に

を置いて、その配下に各ページの HTML を書き出しています。 つまり amp-story タグを body 直下に置くことは実質不可能だと思われます。 (試しに devtools で
あたりを外して amp-story を body 直下にしたら表示されました。)

gatsby で HTML 構造の話もされていましたが、こちらも特に進捗はないようです。 No HTML markup for programmatically created pages · Issue #7648 · gatsbyjs/gatsby · GitHub

そうなると、残念ながら gatsby では amp-story を動かすことは実質不可能ということになります。

まとめ

GatsbyGatsby + AMP 化について調べてみました。 Gatsby で簡単に記事を書いてデプロイするまでは超高速にできそうなので、 簡易的なブログやドキュメントを公開するにはとても良さそうに思いました。

AMP 化についてはギリギリ使えるか使えないか、といったところかなという印象です。 単純なブログ記事のAMP化については問題なさそうですが、 公式サポートされているわけではないので入れるメリットより入れたときの不安定さの方が強そうかなと思いました。

Webストーリーを使うことは難しそうです。 今回はWebストーリーしかみてませんが、 他のAMPコンポーネントを使おうとしても苦しむことがあ流かもしれないなと思いました。