執行役員 CPO (Chief Productivity Officer)の @hsbt です。
しばらく前になりますが、このテックブログをAMP(Accelerated Mobile Pages)対応したので、どのように進めたのかをご紹介します。
AMP 対応したページの作成方法の調査
このテックブログは Ruby の静的ホームページジェネレータの middleman で作成されています。最初は middleman のプラグインなどで、Gemfile に追加するだけで AMP に対応したページを生成できるのではと思い、探してみましたがこれだというプラグインを見つけることはできませんでした。
この時点ではそもそも AMP とはどのような HTML を生成すれば良いのか、ということ自体をわたし自身が正しく理解していませんでした。そこで、 middleman と AMP というキーワードで見つけた以下の二つのページから AMP を理解しつつ、やるべき事を洗い出して行くことにしました。
- adekbadek/amp-mm: Middleman Accelerated Mobile Pages boilerplate
- middleman-blogをAMP対応させる blog.katsuma.tv
これらのエントリを改めて読むことで middleman における AMP 対応は以下のように行えば良いのだという事を理解しました(勝間さんのブログに書かれている内容も含みます)
- middleman は静的ジェネレータのため、AMP に対応した HTML は別の url として作成する
- AMP 対応した HTML を示す url を head の link タグに
rel=amphtml
として入れる - AMP 対応した HTML を通常の
middleman build
と同時に生成するようにタスクにフックを入れる
次の章では上記の 3 つの対応について順番に紹介します。
middleman の AMP 対応
middleman が生成した HTML を nokogiri で書き換える
middleman 本体やテンプレートに手を入れることで middleman を用いて AMP に対応した HTML を生成することは可能ですが、今回は Ruby の XML パーサーである nokogiri を用いて、一旦生成済みの HTML をインプットとして、AMP の仕様に準拠するように DOM を全て書き換えた上で AMP 用の HTML を出力し保存することにしました。以下が、実際に AMP 対応をするためのコードの一部です。
# html_path は書き換える html が存在するファイルパス、html は html 本体
def ampnize(html_path, html)
# CSS は外部参照ではなく HTML 本体に埋め込みます
stylesheet_link_regex = /<link href="([..\/]*?stylesheets\/[\w\-]*\.css)" rel="stylesheet" \/>/
inline_stylesheet = File.read('build' + html.match(stylesheet_link_regex)[1])
html.gsub!(stylesheet_link_regex, '<style amp-custom>'+ inline_stylesheet + '</style>')
html = Nokogiri::HTML(html)
# amphtml を canonical に書き換えます
canonical = html.css('link[rel=amphtml]')[0]
canonical['rel'] = "canonical"
canonical['href'] = canonical['href'].gsub(/amp\//, '')
# AMP ページではソーシャルボタンは AMP 仕様に沿ったものしか使えないので全部取り除きます
html.search('.hatena-bookmark').remove
html.search('.fb-share-button').remove
html.search('.pocket').remove
# inline な style は AMP では使えないので消します
html.search('.//@style').remove
# br に clear 属性は許されていないそうです
html.search('.//br').each{|e| e.attributes['clear'].remove if e['clear'] }
# target=blank は AMP では使えないので _blank に置き換えます
html.search('.//@target').each{|e| e.value = "_blank" if e.value == "blank" }
...(省略)
html.to_s
上記のようなコードを用いて middleman で生成された HTML ファイルを読み込み、新しく生成した HTML が The AMP Validator で valid と判定されるまで html の書き換えを繰り返しました。上記に示した以外の書き換え対応としては img タグの置き換えや Google Analytics のコードの置き換え、AMP 対応したソーシャルウィジェットの配置などを行っています。
middleman が生成する HTML に amphtml 属性を付与する
続いて、AMP ページの URL を通常の HTML に埋め込みます。これは middleman が提供している layout ファイルを変更し、rel 属性の値として amphtml という値を持つタグを埋め込みました。
doctype html
html
head
meta charset="utf-8"
meta http-equiv="X-UA-Compatible" content="IE=edge;chrome=1"
meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,user-scalable=no"
link rel='amphtml' href="https://tech.pepabo.com/amp/#{current_page.path.sub(/blog\//, '').sub(/index.html/, '')}"
...(省略)
この "rel=amphtml" のタグは最初に紹介した ampnize メソッドによって、AMP 対応の HTML では "rel=canonical" になるように書き換えを行っています。
AMP 対応 HTML の生成
最後に AMP 対応の HTML を通常の middleman build
コマンドの実行時に生成するようにフックを入れます。まず、AMP 化する対象のページとして middleman-blog の記事である Middleman::Blog::BlogArticle
のみを対象とするように、amp-mmのコードを変更した上で、対象ページを after_build
フックを用いて AMP 化しています。
# For AMP: https://github.com/adekbadek/amp-mm/
PAGES_TO_AMP = []
#
# https://middlemanapp.com/advanced/sitemap/#using-the-sitemap-in-config-rb
ready do
sitemap.resources.each do |page|
# XXX https://github.com/middleman/middleman-blog/blob/master/lib/middleman-blog/blog_article.rb#L344
next unless page.inspect =~ /Middleman::Blog::BlogArticle/
amp_page_path = page.path.gsub(/^blog\//, '')
proxy "/amp/#{amp_page_path}", page.path
PAGES_TO_AMP.push(amp_page_path)
end
end
after_build do
PAGES_TO_AMP.each do |name|
amp_page = "build/amp/#{name}"
html = File.read("build/#{name}")
amp_html = ampnize(amp_page, html)
File.write(amp_page, amp_html)
end
end
ここまでの対応を全て終えると tech.pepabo.com/amp/...
配下に AMP 対応された HTML が出力されます。
継続的な AMP 対応の検証
ひとまずファーストステップとして AMP 対応は終えましたが、将来にわたって作成されるエントリ全てが AMP として準拠している事を保証するために amphtml-validator という npm モジュールを CI に入れ、middleman build
によって生成される AMP 対応 HTML が AMP として valid であるかを継続的に確認するようにしました。以下はコマンドの例です。
- npm -g install amphtml-validator
- amphtml-validator build/amp/*/*/*/*/*.html
まとめ
Ruby の静的ホームページジェネレータの middleman で生成されているサイトを AMP 対応させる方法についてご紹介しました。今回は記事のみの対応でしたが、今後はトップページやカテゴリページなどサイト全ての AMP 対応や nokogiri を用いた書き換えではない middleman のプラグインとして生成する仕組みなどについて取り組んでいきます。